按值排列的紧凑型对象数组(Jquery 或下划线)
Compact Array of objects by value (Jquery or Underscore)
我有一个对象数组:
"Entries" : [ {
"FieldName" : "Name1",
"FieldValue" : "N1Value1"
}, {
"FieldName" : "Name1",
"FieldValue" : "N1Value2"
}, {
"FieldName" : "Name1",
"FieldValue" : "N1Value3"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value1"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value2"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value3"
}, {
"FieldName" : "Name3",
"FieldValue" : "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue" : "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue" : "N5Value1"
} ]
我想把它改造成:
"Entries" : [ {
"FieldName" : "Name1",
"FieldValue" : ["N1Value1","N1Value2","N1Value3"]
}, {
"FieldName" : "Name2",
"FieldValue" : ["N2Value1", "N2Value2", "N2Value3"]
}, {
"FieldName" : "Name3",
"FieldValue" : "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue" : "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue" : "N5Value1"
} ]
我尝试首先在数组中使用唯一的 FieldName 值,然后在 JSON 数组中使用 _.filter 以尝试接收 return 中的数组,但所有我得到的是整个对象。
$.each(arrUniqueFieldNames, function() {
var strFName = String(this);
oEntries[this] = _.filter(jsonEntries, function (item) {
if (item.FieldName === strFName) {
return String(item.FieldValue)
}
});
});
此代码中可能存在一些不完善之处,但它并没有像我预期的那样工作,因为它 return 是整个对象,而不仅仅是值。
我也尝试用 _.map 替换 _.filter,结果是我为每个数组得到了很多 "undefined".
我知道你想要 jquery 但我不太确定所以我给你一个纯 JavaScript 的解决方案:
test = [ {
"FieldName" : "Name1",
"FieldValue" : "N1Value1"
}, {
"FieldName" : "Name1",
"FieldValue" : "N1Value2"
}, {
"FieldName" : "Name1",
"FieldValue" : "N1Value3"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value1"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value2"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value3"
}, {
"FieldName" : "Name3",
"FieldValue" : "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue" : "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue" : "N5Value1"
} ];
result =[];
for (i=0; i<test.length; i++)
{
element=test[i];
key=element['FieldName'];
value=element['FieldValue'];
if (!(key in result))
result[key] = [value];
else
result[key].push(value);
}
console.log(result);
另一个可能更好的 reusable/maintainable 解决方案,它也是纯粹基于语言核心的,可以使用 Array.prototype.reduce
然后可能看起来像那样 ...
var entries = [{
"FieldName" : "Name1",
"FieldValue": "N1Value1"
}, {
"FieldName" : "Name1",
"FieldValue": "N1Value2"
}, {
"FieldName" : "Name1",
"FieldValue": "N1Value3"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value1"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value2"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value3"
}, {
"FieldName" : "Name3",
"FieldValue": "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue": "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue": "N5Value1"
}];
function collectAndGroupValuesOfEquallyNamedFieldItems (collector, fieldItem) {
var
fieldName = fieldItem.FieldName,
itemGroup = collector.map[fieldName];
if (!itemGroup) {
itemGroup = collector.map[fieldName] = {
"FieldName" : fieldName,
"FieldValue": []
};
collector.list.push(itemGroup);
}
itemGroup.FieldValue.push(fieldItem.FieldValue);
return collector;
}
entries = entries.reduce(collectAndGroupValuesOfEquallyNamedFieldItems, {
map: {},
list: []
}).list;
console.log('entries : ', entries);
.as-console-wrapper { max-height: 100%!important; top: 0; }
附录/编辑
@Paprika ... 考虑到@rockstar 的最后评论,上述解决方案也识别 FieldValue
的双重数据结构 - {String}
单个 FieldValue
的值] 值和 {Array<String>}
用于多个 FieldValue
值 - 确实更改为 ...
var entries = [{
"FieldName" : "Name1",
"FieldValue": "N1Value1"
}, {
"FieldName" : "Name1",
"FieldValue": "N1Value2"
}, {
"FieldName" : "Name1",
"FieldValue": "N1Value3"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value1"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value2"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value3"
}, {
"FieldName" : "Name3",
"FieldValue": "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue": "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue": "N5Value1"
}];
function collectAndGroupValuesOfEquallyNamedFieldItems (collector, fieldItem) {
var
fieldName = fieldItem.FieldName,
itemGroup = collector.map[fieldName];
if (!itemGroup) {
itemGroup = collector.map[fieldName] = {
"FieldName" : fieldName,
"FieldValue": null
};
collector.list.push(itemGroup);
}
if (Array.isArray(itemGroup.FieldValue)) { // list/array of multiple string values.
itemGroup.FieldValue.push(fieldItem.FieldValue);
} else if (typeof itemGroup.FieldValue === 'string') { // data structure switch.
itemGroup.FieldValue = [itemGroup.FieldValue, fieldItem.FieldValue]
} else if (itemGroup.FieldValue === null) { // initial string value.
itemGroup.FieldValue = fieldItem.FieldValue;
}
return collector;
}
entries = entries.reduce(collectAndGroupValuesOfEquallyNamedFieldItems, {
map: {},
list: []
}).list;
console.log('entries : ', entries);
.as-console-wrapper { max-height: 100%!important; top: 0; }
我有一个对象数组:
"Entries" : [ {
"FieldName" : "Name1",
"FieldValue" : "N1Value1"
}, {
"FieldName" : "Name1",
"FieldValue" : "N1Value2"
}, {
"FieldName" : "Name1",
"FieldValue" : "N1Value3"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value1"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value2"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value3"
}, {
"FieldName" : "Name3",
"FieldValue" : "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue" : "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue" : "N5Value1"
} ]
我想把它改造成:
"Entries" : [ {
"FieldName" : "Name1",
"FieldValue" : ["N1Value1","N1Value2","N1Value3"]
}, {
"FieldName" : "Name2",
"FieldValue" : ["N2Value1", "N2Value2", "N2Value3"]
}, {
"FieldName" : "Name3",
"FieldValue" : "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue" : "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue" : "N5Value1"
} ]
我尝试首先在数组中使用唯一的 FieldName 值,然后在 JSON 数组中使用 _.filter 以尝试接收 return 中的数组,但所有我得到的是整个对象。
$.each(arrUniqueFieldNames, function() {
var strFName = String(this);
oEntries[this] = _.filter(jsonEntries, function (item) {
if (item.FieldName === strFName) {
return String(item.FieldValue)
}
});
});
此代码中可能存在一些不完善之处,但它并没有像我预期的那样工作,因为它 return 是整个对象,而不仅仅是值。
我也尝试用 _.map 替换 _.filter,结果是我为每个数组得到了很多 "undefined".
我知道你想要 jquery 但我不太确定所以我给你一个纯 JavaScript 的解决方案:
test = [ {
"FieldName" : "Name1",
"FieldValue" : "N1Value1"
}, {
"FieldName" : "Name1",
"FieldValue" : "N1Value2"
}, {
"FieldName" : "Name1",
"FieldValue" : "N1Value3"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value1"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value2"
}, {
"FieldName" : "Name2",
"FieldValue" : "N2Value3"
}, {
"FieldName" : "Name3",
"FieldValue" : "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue" : "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue" : "N5Value1"
} ];
result =[];
for (i=0; i<test.length; i++)
{
element=test[i];
key=element['FieldName'];
value=element['FieldValue'];
if (!(key in result))
result[key] = [value];
else
result[key].push(value);
}
console.log(result);
另一个可能更好的 reusable/maintainable 解决方案,它也是纯粹基于语言核心的,可以使用 Array.prototype.reduce
然后可能看起来像那样 ...
var entries = [{
"FieldName" : "Name1",
"FieldValue": "N1Value1"
}, {
"FieldName" : "Name1",
"FieldValue": "N1Value2"
}, {
"FieldName" : "Name1",
"FieldValue": "N1Value3"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value1"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value2"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value3"
}, {
"FieldName" : "Name3",
"FieldValue": "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue": "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue": "N5Value1"
}];
function collectAndGroupValuesOfEquallyNamedFieldItems (collector, fieldItem) {
var
fieldName = fieldItem.FieldName,
itemGroup = collector.map[fieldName];
if (!itemGroup) {
itemGroup = collector.map[fieldName] = {
"FieldName" : fieldName,
"FieldValue": []
};
collector.list.push(itemGroup);
}
itemGroup.FieldValue.push(fieldItem.FieldValue);
return collector;
}
entries = entries.reduce(collectAndGroupValuesOfEquallyNamedFieldItems, {
map: {},
list: []
}).list;
console.log('entries : ', entries);
.as-console-wrapper { max-height: 100%!important; top: 0; }
附录/编辑
@Paprika ... 考虑到@rockstar 的最后评论,上述解决方案也识别 FieldValue
的双重数据结构 - {String}
单个 FieldValue
的值] 值和 {Array<String>}
用于多个 FieldValue
值 - 确实更改为 ...
var entries = [{
"FieldName" : "Name1",
"FieldValue": "N1Value1"
}, {
"FieldName" : "Name1",
"FieldValue": "N1Value2"
}, {
"FieldName" : "Name1",
"FieldValue": "N1Value3"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value1"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value2"
}, {
"FieldName" : "Name2",
"FieldValue": "N2Value3"
}, {
"FieldName" : "Name3",
"FieldValue": "N3Value1"
}, {
"FieldName" : "Name4",
"FieldValue": "N4Value1"
}, {
"FieldName" : "Name5",
"FieldValue": "N5Value1"
}];
function collectAndGroupValuesOfEquallyNamedFieldItems (collector, fieldItem) {
var
fieldName = fieldItem.FieldName,
itemGroup = collector.map[fieldName];
if (!itemGroup) {
itemGroup = collector.map[fieldName] = {
"FieldName" : fieldName,
"FieldValue": null
};
collector.list.push(itemGroup);
}
if (Array.isArray(itemGroup.FieldValue)) { // list/array of multiple string values.
itemGroup.FieldValue.push(fieldItem.FieldValue);
} else if (typeof itemGroup.FieldValue === 'string') { // data structure switch.
itemGroup.FieldValue = [itemGroup.FieldValue, fieldItem.FieldValue]
} else if (itemGroup.FieldValue === null) { // initial string value.
itemGroup.FieldValue = fieldItem.FieldValue;
}
return collector;
}
entries = entries.reduce(collectAndGroupValuesOfEquallyNamedFieldItems, {
map: {},
list: []
}).list;
console.log('entries : ', entries);
.as-console-wrapper { max-height: 100%!important; top: 0; }