28 July 2019
Angular (43) -- Add Update and Delete Recipes
by Jerry Zhang
LeetCode Day 23: P168. Excel Sheet Column Title (Easy)
题目:
给一个整数,求在Excel sheet中对应的大字字母列号。
1 -> A
2 -> B
3 -> C
...
26 -> Z
27 -> AA
28 -> AB
我的思路:
一个字母可以表示从1到26,两个字母可以是2626个,三个字母有2626*26个。所以其实是一个等比数列求和公式。 但是不知道有多少项,也就是不知道有多少位。所以一个一个减掉,看还剩下多少。但是如果这个整数非常大,接近整数的最大值,可能会有bug。 所以这种情况要尽可能考虑进去。
想了半个来小时,突然意识到其实这东西就是26进制。。。
后来发现跟26进制还是有一点区别,因为如果A代表0的话,那AA就没意义了。花了三四个小时,终于没有bug了。。。
我的代码:
public class E_168_ExcelSheetColumnTitle {
public static String convertToTitle(int n) {
String result = "";
while (n / 26 > 0) {
result = (char) (65 + (n - 1) % 26) + result;
if (n % 26 == 0) {
n = n - 26;
}
n = n / 26;
}
if (n != 0) {
result = (char) (65 + (n - 1) % 26) + result;
}
return result;
}
public static void main(String[] args) {
for (int i = 0; i < 800; i++) {
String s = convertToTitle(i + 1);
System.out.println(s);
}
}
}
最优解:
class Solution {
public String convertToTitle(int n) {
StringBuilder sb = new StringBuilder();
while (n > 0) {
n--;
int cur = n % 26;
char c = (char)('A' + cur);
sb.insert(0, c);
n /= 26;
}
return sb.toString();
}
}
跟我的思路差不多,但是他比我的简洁。我的错误在于把最后一种情况单独讨论了。如果合并到while循环里,就简单很多了。
把我的代码改造一下
public class E_168_ExcelSheetColumnTitle {
public String convertToTitle(int n) {
String result = "";
while (n > 0) {
n--;
result = (char) ('A' + n % 26) + result;
n = n / 26;
}
return result;
}
}
Angular:
Create Actions:
The code was already copied in the previous blogs:
export const ADD_RECIPE = '[Recipe] Add Recipe';
export const UPDATE_RECIPE = '[Recipe] Update Recipe';
export const DELETE_RECIPE = '[Recipe] Delete Recipe';
export class AddRecipe implements Action {
readonly type = ADD_RECIPE;
constructor(public payload: Recipe) {}
}
export class UpdateRecipe implements Action {
readonly type = UPDATE_RECIPE;
constructor(public payload: {index: number; newRecipe: Recipe}) {}
}
export class DeleteRecipe implements Action {
readonly type = DELETE_RECIPE;
constructor(public payload: number) {}
}
Reducer
case RecipesActions.ADD_RECIPE:
return {
...state,
recipes: [...state.recipes, action.payload]
};
case RecipesActions.UPDATE_RECIPE:
const updatedRecipe = {
...state.recipes[action.payload.index],
...action.payload.newRecipe
};
const updatedRecipes = [...state.recipes];
updatedRecipes[action.payload.index] = updatedRecipe;
return {
...state,
recipes: updatedRecipes
};
case RecipesActions.DELETE_RECIPE:
return {
...state,
recipes: state.recipes.filter((recipe, index) => {
return index !== action.payload;
})
};
Dispatch these actions:
When submitting a recipe, we no longer use a service, but use a store instead to dispatch a new Action.
In recipe edit component:
onSubmit() {
if (this.editMode) {
// this.recipeService.updateRecipe(this.id, this.recipeForm.value);
this.store.dispatch(
new RecipesActions.UpdateRecipe({
index: this.id,
newRecipe: this.recipeForm.value
})
);
} else {
// this.recipeService.addRecipe(this.recipeForm.value);
this.store.dispatch(new RecipesActions.AddRecipe(this.recipeForm.value));
}
this.onCancel();
}
In recipe detail component:
onDeleteRecipe() {
// this.recipeService.deleteRecipe(this.id);
this.store.dispatch(new RecipesActions.DeleteRecipe(this.id));
this.router.navigate(['/recipes']);
}
In the recipe resolver service:
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
Observable<Recipe[]> | Promise<Recipe[]> | Recipe[] {
return this.store.select('recipes').pipe(
take(1),
map(recipesState => {
return recipesState.recipes;
}),
switchMap(recipes => {
if (recipes.length === 0) {
this.store.dispatch(new RecipesActions.FetchRecipes());
return this.actions$.pipe(
ofType(RecipesActions.SET_RECIPES),
take(1)
);
} else {
return of(recipes);
}
})
);
}
In recipe edit component, we need to unsubscribe.
private storeSub: Subscription;
if (this.editMode) {
// const recipe = this.recipeService.getRecipe(this.id);
this.storeSub = this.store
.select('recipes')
.pipe(
map(recipeState => {
return recipeState.recipes.find((recipe, index) => {
return index === this.id;
});
})
)
.subscribe(recipe => {
recipeName = recipe.name;
recipeImagePath = recipe.imagePath;
recipeDescription = recipe.description;
if (recipe.ingredients) {
for (const ingredient of recipe.ingredients) {
recipeIngredients.push(
new FormGroup({
'name': new FormControl(ingredient.name, Validators.required),
'amount': new FormControl(ingredient.amount, [
Validators.required,
Validators.pattern(/^[1-9]+[0-9]*$/)
])
})
);
}
}
});
}
ngOnDestroy(): void {
if (this.storeSub) {
this.storeSub.unsubscribe();
}
}