#javascript #arrays #angular #multidimensional-array #data-structures
Вопрос:
Я работаю с API, который возвращает варианты оплаты за услугу. Варианты оплаты: (1 год услуги, оплачивается ежемесячно), (1 год услуги, авансом), (2 года услуги, оплачивается ежемесячно), (2 года услуги, авансом). Данные возвращаются следующим образом:
options = [
{ price: 10,
serviceLength: "1 year",
paymentFrequency: "monthly payment",
},
{ price: 100,
serviceLength: "1 year",
paymentFrequency: "one-time payment",
},
{ price: 8,
serviceLength: "2 year",
paymentFrequency: "monthly payment",
},
{ price: 150,
serviceLength: "2 year",
paymentFrequency: "one-time payment",
},
]
Мне нужно отобразить данные таким образом, чтобы объединить параметры обслуживания за 1 год и параметры обслуживания за 2 года вместе. Что-то вроде этого:
Срок Службы 1 Год
- Ежемесячно — $XX.XX
- Авансовый платеж: $XX.XX
2 Года Службы
- Ежемесячно — $XX.XX
- Авансовый платеж: $XX.XX
Каков наилучший способ организации данных для этого? В будущем, вероятно, будут добавлены дополнительные варианты цен. Я думал о том, чтобы создать функцию для разделения длин года, а затем создать цикл double for для отображения вариантов?
Что-то вроде:
oneYearOptions = [
{ price: 10,
serviceLength: "1 year",
paymentFrequency: "monthly payment",
},
{ price: 100,
serviceLength: "1 year",
paymentFrequency: "one-time payment",
},
twoYearOptions = [
{ price: 8,
serviceLength: "2 year",
paymentFrequency: "monthly payment",
},
{ price: 150,
serviceLength: "2 year",
paymentFrequency: "one-time payment",
},
];
const allOptions = [oneYearOptions, twoYearOptions];
и тогда угловые ts будут чем-то вроде:
<div *ngFor="let option of allOptions>
<div *ngFor="let priceOption of priceOptions">
{{ list the data in here }}
</div>
</div>
Мне это просто кажется неэффективным. Есть ли лучший способ сделать это? Может быть, вместо этого использовать хэш-карту?
Комментарии:
1. Честно говоря, это кажется разумным способом сделать это, учитывая, что у вас нет контроля над форматом возвращаемых данных API. Возможно, вам удастся сэкономить немного памяти, не разделяя массив на несколько массивов, но я не думаю, что в этом действительно есть необходимость. Что касается быстродействия, вам придется зацикливаться на каждом элементе и отображать его независимо, поэтому вы не можете сделать лучше, чем «зацикливаться на каждом элементе».
2. Если вы можете изменить данные, вы можете сделать это в одном цикле, если хотите. У вас может быть массив с объектами, где объекты могут иметь тип «заголовок» или параметры (где параметр-это объект, который у вас есть сейчас).
Ответ №1:
просто объект, имеющий в качестве свойства «параметры» , который является массивом
options =
{serviceLength: "1 year",
options:[
{ price: 10,
paymentFrequency: "monthly payment",
},
{ price: 100,
paymentFrequency: "one-time payment",
}]
},
{ serviceLength: "2 year",
options:[
{ price: 8,
paymentFrequency: "monthly payment",
},
{ price: 150,
paymentFrequency: "one-time payment",
}]
}
]
Это правда, что если вы храните данные в базе данных, такой как ваш первый массив объектов, хорошо преобразовать их в другой способ, используя reduce
this.options=this.data.reduce((a:any,b:any)=>{
const el=a.find(x=>x.serviceLength==b.serviceLength)
if (el){
el.options=[...el.options,{price:b.price,paymentFrequency:b.paymentFrequency}]
return a;
}
return [...a,{serviceLength:b.serviceLength,options:[{price:b.price,paymentFrequency:b.paymentFrequency}]}]
},[])
Файл .html становится похожим
<div *ngFor="let option of options">
<div>{{option.serviceLength}}</div>
<!--see the inner .html loop over "option.options"-->
<div *ngFor="let priceOption of option.options">
{{ priceOption.price}} {{priceOption.paymentFrecuency}}
</div>
</div>
Ответ №2:
Вы также можете перебирать отфильтрованные версии своего массива, если вам не хочется манипулировать данными:
<div *ngFor="let option of options.filter(option => option.serviceLength == '1 year')">
{{ list the data in here }}
</div>
<div *ngFor="let option of options.filter(option => option.serviceLength == '2 year')">
{{ list the data in here }}
</div>
Ответ №3:
Я думаю, что мы можем использовать трубу groupBy здесь.
import { Component, Pipe, PipeTransform } from "@angular/core";
@Pipe({
name:"groupBy"
})
export class GroupBy implements PipeTransform {
transform(array: any[]) : number {
return array.reduce((trasnformedOption, { serviceLength })=>{
if(!trasnformedOption.some(option => option.serviceLength === serviceLength)){
trasnformedOption.push({
serviceLength ,
serviceDetails : array.filter(v=>v.serviceLength === serviceLength)
});
}
return trasnformedOption;
},[]);
}
}
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
options = [
{ price: 10,
serviceLength: "1 year",
paymentFrequency: "monthly payment",
},
{ price: 100,
serviceLength: "1 year",
paymentFrequency: "one-time payment",
},
{ price: 8,
serviceLength: "2 year",
paymentFrequency: "monthly payment",
},
{ price: 150,
serviceLength: "2 year",
paymentFrequency: "one-time payment",
},
];
}
app.component.html
<div>
<div *ngFor="let option of options | groupBy">
{{ option.serviceLength }}
<div *ngFor="let details of option.serviceDetails">
{{ details.paymentFrequency}} - {{ details.price }}
</div>
</div>
</div>