Javascript 将数组按多个字段分组
我有一个api响应,如下所示:Javascript 将数组按多个字段分组,javascript,angular,Javascript,Angular,我有一个api响应,如下所示: people = [ { name: 'John', surname: 'Doe', pet: { type: 'CAT', name: 'whiskers', age: 1 } }, { name: 'John', surname: 'Doe', pet: { type: 'DOG
people = [
{
name: 'John',
surname: 'Doe',
pet: {
type: 'CAT',
name: 'whiskers',
age: 1
}
},
{
name: 'John',
surname: 'Doe',
pet: {
type: 'DOG',
name: 'Dexter',
age: 4
}
},
{
name: 'Jane',
surname: 'Doe',
pet: {
type: 'CAT',
name: 'Fluffy',
age: 10
}
},
{
name: 'Jane',
surname: 'Doe',
pet: {
type: 'CAT',
name: 'Dennis',
age: 3
}
}
]
我想把它翻译成这样(只有两种宠物):
我用的是角度5。我需要能够显示一张类似以下内容的表格:
<table>
<thead>
<tr>
<th>Name</th>
<th>Surname</th>
<th>Cats</th>
<th>Dogs</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let person of people">
<td>{{person.name}}</td>
<td>{{person.surname}}</td>
<td>
<ul>
<li *ngFor="let cat of person.cats">name: {{cat.name}}, age: {{cat.age}} years</li>
</ul>
</td>
<td>
<ul>
<li *ngFor="let dog of person.dogs">name: {{dog.name}}, age: {{dog.age}} years</li>
</ul>
</td>
</tr>
</tbody>
</table>
理想情况下,我将被允许更改api,以便此逻辑位于服务器端。同时,我想知道如何做到这一点。您可以使用
reduce
将数据汇总到一个对象。使用Object.values
将对象转换为数组
let people=[{姓名:'John',姓氏:'Doe',宠物:{类型:'CAT',姓名:'胡须',年龄:1}},{姓名:'John',姓氏:'Doe',宠物:{类型:'DOG',姓名:'Dexter',年龄:4},{姓名:'Jane',姓氏:'Dennis',宠物:{类型:'CAT',姓名:'Fluffy',年龄:10},{姓名:'Jane',姓氏:'Doe',宠物:{类型:'CAT',姓氏:'Dennis',年龄:3}];
让result=Object.values(people.reduce((c,{pet,{u})=>{
让k=u.name+u.姓氏;//使用name和last name制作一个键
让{type,…p}=pet;//解构pet对象
type=type.toLowerCase();//使类型小写
c[k]=c[k]| | u;//如果名称不存在,则启动
c[k][type]=c[k][type]| |【】//如果宠物不存在,则启动
c[k][type].push(p);//添加宠物
返回c;
}, {}));
控制台日志(结果)代码>
确定组的答案:
首先,我们创建具有所需对象结构的数组
var newPeople = people.map(function(item){
var newPeople = {};
newPeople.name = item.name;
newPeople.surname = item.surname;
var type = item.pet.type;
newPeople[type] = [];
var petDetails = {
name: item.pet.name,
age: item.pet.age
}
newPeople[type].push(petDetails);
return newPeople;
});
/*Output: people = [{name: "John", surname: "Doe", CAT: Array(1)},
{name: "John", surname: "Doe", DOG: Array(1)},
{name: "Jane", surname: "Doe", CAT: Array(1)},
{name: "Jane", surname: "Doe", CAT: Array(1)}]*/
现在,我们将使用以下循环对它们进行分组:
for (var i = 0; i < newPeople.length; i++) {
for(var j = i+1; j < newPeople.length;j++){
var item = newPeople[i];
var nextItem = newPeople[j];
if(item.name === nextItem.name && item.surname === nextItem.surname) {
var firstItemKeys = Object.keys(item);
var nextItemKeys = Object.keys(nextItem);
if(firstItemKeys[2] === nextItemKeys[2]) {
item[firstItemKeys[2]].push(nextItem[nextItemKeys[2]][0]);
} else {
if (Array.isArray(item[nextItemKeys[2]])) {
item[nextItemKeys[2]].push(nextItem[nextItemKeys[2]][0]);
} else {
item[nextItemKeys[2]] = [];
item[nextItemKeys[2]].push(nextItem[nextItemKeys[2]][0]);
}
}
newPeople.splice(j,1);
j--
}
}
}
我将通过减少数组来实现这一点([参见array.prototype.reduce][1]
[1] :)
基本上,在遍历“人员”数据中的每个(当前)对象时创建聚合结果数组。检查是否存在具有person键的对象。如果有,则将新宠物添加到相应的宠物阵列中。否则,用当前宠物创建一个新的人
确保使用空数组初始化reduce函数(调用groupByPerson时的第二个参数)
如果您能够在整理API时使用库过渡,那么有一个函数可以为您处理这个问题。
var newPeople = people.map(function(item){
var newPeople = {};
newPeople.name = item.name;
newPeople.surname = item.surname;
var type = item.pet.type;
newPeople[type] = [];
var petDetails = {
name: item.pet.name,
age: item.pet.age
}
newPeople[type].push(petDetails);
return newPeople;
});
/*Output: people = [{name: "John", surname: "Doe", CAT: Array(1)},
{name: "John", surname: "Doe", DOG: Array(1)},
{name: "Jane", surname: "Doe", CAT: Array(1)},
{name: "Jane", surname: "Doe", CAT: Array(1)}]*/
for (var i = 0; i < newPeople.length; i++) {
for(var j = i+1; j < newPeople.length;j++){
var item = newPeople[i];
var nextItem = newPeople[j];
if(item.name === nextItem.name && item.surname === nextItem.surname) {
var firstItemKeys = Object.keys(item);
var nextItemKeys = Object.keys(nextItem);
if(firstItemKeys[2] === nextItemKeys[2]) {
item[firstItemKeys[2]].push(nextItem[nextItemKeys[2]][0]);
} else {
if (Array.isArray(item[nextItemKeys[2]])) {
item[nextItemKeys[2]].push(nextItem[nextItemKeys[2]][0]);
} else {
item[nextItemKeys[2]] = [];
item[nextItemKeys[2]].push(nextItem[nextItemKeys[2]][0]);
}
}
newPeople.splice(j,1);
j--
}
}
}
newPeople = [{name: "John", surname: "Doe", CAT: Array(1), DOG: Array(1)},
{name: "Jane", surname: "Doe", CAT: Array(2)}]
let people = [{name: 'John',surname: 'Doe',pet: {type: 'CAT',name: 'whiskers',age: 1}},{name: 'John',surname: 'Doe',pet: {type: 'DOG', name: 'Dexter',age: 4}},{name: 'Jane',surname: 'Doe',pet: {type: 'CAT',name: 'Fluffy',age: 10}},{name: 'Jane',surname: 'Doe',pet: {type: 'CAT',name: 'Dennis',age: 3}}];
function groupByPerson(data) {
return data.reduce( function (results, current) {
const key = current.name + "_" + current.surname;
let matched = results.filter(r => r.key === key)[0];
if (matched) {
let petArray = (current.pet.type === "CAT") ? matched.cats : matched.dogs;
petArray.push({name:current.pet.name, age:current.pet.age});
}
else {
let newPerson = {
key: key,
name: current.name,
surname: current.surname,
cats: [],
dogs: []
}
let petArray = (current.pet.type === "CAT") ? newPerson.cats : newPerson.dogs;
petArray.push({name:current.pet.name, age:current.pet.age});
results.push(newPerson);
}
return results;
}, []); // initialize with empty array
}
const results = groupByPerson(people);