英文:
filtering array with multiple same properties
问题
以下是您要翻译的内容:
const foodsList = [
{
foodOrigin: "Padang",
foodName: "Nasi Padang",
originCode: "PDN"
},
{
foodOrigin: "Padang",
foodName: "Gulai",
originCode: "PDN"
},
{
foodOrigin: "Padang",
foodName: "Rendang",
originCode: "PDN"
},
{
foodOrigin: "Palembang",
foodName: "Pempek",
originCode: "PLG"
},
{
foodOrigin: "Palembang",
foodName: "Tekwan",
originCode: "PLG"
},
{
foodOrigin: "Yogyakarta",
foodName: "Gudeg",
originCode: "YKT"
}
];
const filteredFoodsList = [
{
foodOrigin: "Padang",
originCode: "PDN"
},
{
foodOrigin: "Palembang",
originCode: "PLG"
},
{
foodOrigin: "Yogyakarta",
originCode: "YKT"
}
];
为了实现这个结果,我尝试了以下方法,但是否有更清晰和更好的方法来做到这一点(尤其是因为我的实际数组数据超过500个):
const filteredFoodsList = [];
for (let i = 0; i < foodsList.length; i++) {
if (i === 0) {
filteredFoodsList.push({
originCode: foodsList[i].originCode,
foodOrigin: foodsList[i].foodOrigin
});
}
let isExist = false;
for (let j = 0; j < filteredFoodsList.length; j++) {
if (foodsList[i].originCode === filteredFoodsList[j].originCode) {
isExist = true;
}
}
if (!isExist) {
filteredFoodsList.push({
originCode: foodsList[i].originCode,
foodOrigin: foodsList[i].foodOrigin
});
}
}
英文:
so I have an array of values like this
const foodsList = [
{
foodOrigin: "Padang",
foodName: "Nasi Padang",
originCode: "PDN"
},
{
foodOrigin: "Padang",
foodName: "Gulai",
originCode: "PDN"
},
{
foodOrigin: "Padang",
foodName: "Rendang",
originCode: "PDN"
},
{
foodOrigin: "Palembang",
foodName: "Pempek",
originCode: "PLG"
},
{
foodOrigin: "Palembang",
foodName: "Tekwan",
originCode: "PLG"
},
{
foodOrigin: "Yogyakarta",
foodName: "Gudeg",
originCode: "YKT"
}
];
and I want to filter the array so the result would be like this instead
const filteredFoodsList = [
{
foodOrigin: "Padang",
originCode: "PDN"
},
{
foodOrigin: "Palembang",
originCode: "PLG"
},
{
foodOrigin: "Yogyakarta",
originCode: "YKT"
}
];
In order to achieve the result, I tried doing it like below but is there a cleaner and better way to do this? ( especially since my actual array's data consist of more than 500 )
const filteredFoodsList = [];
for (let i = 0; i < foodsList.length; i++) {
if (i === 0) {
filteredFoodsList.push({
originCode: foodsList[i].originCode,
foodOrigin: foodsList[i].foodOrigin
});
}
let isExist = false;
for (let j = 0; j < filteredFoodsList.length; j++) {
if (foodsList[i].originCode === filteredFoodsList[j].originCode) {
isExist = true;
}
}
if (!isExist) {
filteredFoodsList.push({
originCode: foodsList[i].originCode,
foodOrigin: foodsList[i].foodOrigin
});
}
}
答案1
得分: 5
以下是翻译好的部分:
"Map"可能是收集唯一值的最快方法。
(我借用了Nina的回答中的Array.from(map, ([originCode, foodOrigin]) => ({ foodOrigin, originCode }))
,非常优雅)。
但是这不会影响性能,因为结果数组应该很小。
但她忘记了包括一个Map::has()
检查,这确实显著提高了性能。
重要的是源数组的迭代速度。像往常一样,我看到没有比for(let i = 0; ...)
更快的东西...
还有一个性能基准测试的部分,不过我无法提供相关图像。
英文:
As the OP stated there should be some focus on performance, so..
The Map
could be the fastest way to collect unique values.
(I've borrowed Array.from(map, ([originCode, foodOrigin]) => ({ foodOrigin, originCode }))
from Nina's answer, really elegant).
But it doesn't affect the performance since the resulting array should be quite small.
But she forgot to include a Map::has()
check that really improves the performance significantly.
What's important is how fast the source array is iterated. As always I see there can't be a faster thing than for(let i = 0; ...)
...
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const foodsList=[{foodOrigin:"Padang",foodName:"Gulai",originCode:"PDN"},{foodOrigin:"Padang",foodName:"Rendang",originCode:"PDN"},{foodOrigin:"Palembang",foodName:"Pempek",originCode:"PLG"},{foodOrigin:"Palembang",foodName:"Tekwan",originCode:"PLG"},{foodOrigin:"Yogyakarta",foodName:"Gudeg",originCode:"YKT"}];
const map = new Map;
for (let i = 0; i < foodsList.length; i++) {
const item = foodsList[i];
map.has(item.originCode) || map.set(item.originCode, item.foodOrigin);
}
const result = Array.from(map, ([originCode, foodOrigin]) => ({ foodOrigin, originCode }));
console.log(result);
<!-- end snippet -->
And a benchmark:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-html -->
<script benchmark data-count="1">
const chunk = [{ foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN" }, { foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN" }, { foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG" }, { foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG" }, { foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT" }];
var foodsList = [];
let count = 10000000;
while (count--) {
foodsList.push(...chunk);
}
// @benchmark Peter's solution
foodsList
.reduce((collector, { foodOrigin, originCode = null }) => {
if (originCode !== null && !collector.lookup.has(foodOrigin)) {
collector.lookup.set(foodOrigin, true);
collector.result.push({
foodOrigin,
originCode,
});
}
return collector;
}, { lookup: new Map, result: [] }).result;
// @benchmark Nina's solution
Array.from(
foodsList.reduce((m, { foodOrigin, originCode }) => m.set(foodOrigin, originCode), new Map),
([foodOrigin, originCode]) => ({ foodOrigin, originCode })
);
// @benchmark Alexander's solution
const map = new Map;
for (let i = 0; i < foodsList.length; i++) {
const item = foodsList[i];
map.has(item.originCode) || map.set(item.originCode, item.foodOrigin);
}
Array.from(map, ([originCode, foodOrigin]) => ({ foodOrigin, originCode }));
// @benchmark Nina's improved
Array.from(
foodsList.reduce((m, { foodOrigin, originCode }) => {
m.has(foodOrigin) || m.set(foodOrigin, originCode);
return m;
}, new Map),
([foodOrigin, originCode]) => ({ foodOrigin, originCode })
);
</script>
<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>
<!-- end snippet -->
答案2
得分: 3
你可以使用 Map
并从中获取一个新数组。
const
foodsList = [{ foodOrigin: 'Padang', foodName: 'Gulai', originCode: 'PDN' }, { foodOrigin: 'Padang', foodName: 'Rendang', originCode: 'PDN' }, { foodOrigin: 'Palembang', foodName: 'Pempek', originCode: 'PLG' }, { foodOrigin: 'Palembang', foodName: 'Tekwan', originCode: 'PLG' }, { foodOrigin: 'Yogyakarta', foodName: 'Gudeg', originCode: 'YKT' }],
result = Array.from(
foodsList.reduce((m, { foodOrigin, originCode }) => m.set(foodOrigin, originCode), new Map),
([foodOrigin, originCode]) => ({ foodOrigin, originCode })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
英文:
You could take a Map
and get a new array from it.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const
foodsList = [{ foodOrigin: 'Padang', foodName: 'Gulai', originCode: 'PDN' }, { foodOrigin: 'Padang', foodName: 'Rendang', originCode: 'PDN' }, { foodOrigin: 'Palembang', foodName: 'Pempek', originCode: 'PLG' }, { foodOrigin: 'Palembang', foodName: 'Tekwan', originCode: 'PLG' }, { foodOrigin: 'Yogyakarta', foodName: 'Gudeg', originCode: 'YKT' }],
result = Array.from(
foodsList.reduce((m, { foodOrigin, originCode }) => m.set(foodOrigin, originCode), new Map),
([foodOrigin, originCode]) => ({ foodOrigin, originCode })
);
console.log(result);
<!-- language: lang-css -->
.as-console-wrapper { max-height: 100% !important; top: 0; }
<!-- end snippet -->
答案3
得分: 2
你可以使用一个对象来存储数值。
英文:
You can use an object to store the values
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const foodsList = [{
foodOrigin: 'Padang',
foodCode: 'SPI',
foodName: 'Nasi Padang',
}, {
foodOrigin: 'Padang',
foodName: 'Gulai',
originCode: 'PDN',
}, {
foodOrigin: 'Padang',
foodName: 'Rendang',
originCode: 'PDN',
}, {
foodOrigin: 'Palembang',
foodName: 'Pempek',
originCode: 'PLG',
}, {
foodOrigin: 'Palembang',
foodName: 'Tekwan',
originCode: 'PLG',
}, {
foodOrigin: 'Yogyakarta',
foodName: 'Gudeg',
originCode: 'YKT',
}]
const items = {}
for (const item of foodsList) {
if (item.originCode && !(item.originCode in items)) {
items[item.originCode] = item
}
}
const result = Object.values(items).map(({ originCode, foodName }) => ({ originCode, foodName }))
console.log(result)
<!-- end snippet -->
答案4
得分: 1
以下是您要翻译的内容:
这是我的“老派”方法,没有使用Map
:
const foodsList = [
{ foodOrigin: "Padang", foodCode: "SPI", foodName: "Nasi Padang" },
{ foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN" },
{ foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN" },
{ foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG" },
{ foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG" },
{ foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT" }
];
const filteredFoodsList = foodsList.reduce(
(acc, curr) =>
curr.originCode &&
!acc.some(a => a?.originCode === curr.originCode)
? [...acc, curr]
: acc,
[]
);
console.log(filteredFoodsList);
请注意,我已将原始代码部分保留为英文。
英文:
Here's my "old-fashioned" approach without Map
usage:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const foodsList = [ { foodOrigin: "Padang", foodCode: "SPI", foodName: "Nasi Padang" }, { foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN" }, { foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN" }, { foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG" }, { foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG" }, { foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT" }];
const filteredFoodsList = foodsList.reduce(
(acc, curr) =>
curr.originCode &&
!acc.some(a => a?.originCode === curr.originCode)
? [...acc, curr]
: acc,
[]
);
console.log(filteredFoodsList);
<!-- end snippet -->
答案5
得分: 1
The OP does not filter because not only the array is effected but also each of the array item's data-structure. It's also not mapping, which would allow the latter (changing an item's data), but always assures the same amount of array items.
The combination of filtering and altering data is a classical reduce task.
As for the OP's problem, not only does one need to extract unique item-data from a source-array, one also needs to implement a more bullet-proof solution due to the probable occurrence of incorrect data like ...
{ foodOrigin: "Padang", foodCode: "SPI", foodName: "Nasi Padang" }
... versus its correct notation of ...
{ foodOrigin: "Padang", foodName: "Nasi Padang", originCode: "SPI" }
In order to come up with the least necessary iteration effort, one could implement a single reduce task in a way that one passes as the reduce method's 2nd parameter an object-based initial value which features two key-value pairs with the lookup-key holding a Map-reference and the result-key referencing an array.
With each iteration the callback reducer function receives such an object as its first parameter. It also has to return such an object either with changes to its data or not. The very object's Map reference will be used as one of the fastest possible ways of looking up whether a specific data has been already processed. The implementation would use a map's has method on that behalf.
In case a data-item of interest has not yet been processed, one would set an item specific entry at the very Map-based lookup. Additionally one would create a new, target-data specific object and push it into the result-array.
The latter also features the final result at the reduce task's return value.
英文:
The OP does not filter
because not only the array is effected but also each of the array item's data-structure. It's also not map
ping, which would allow the latter (changing an item's data), but always assures the same amount of array items.
The combination of filtering and altering data is a classical reduce
task.
As for the OP's problem, not only does one need to extract unique item-data from a source-array, one also needs to implement a more bullet-proof solution due to the probable occurrence of incorrect data like ...
{ foodOrigin: "Padang", foodCode: "SPI", foodName: "Nasi Padang"` }
... versus its correct notation of ...
{ foodOrigin: "Padang", foodName: "Nasi Padang", originCode: "SPI" }
In order to come up with the least necessary iteration effort, one could implement a single reduce
task in a way that one passes as the reduce
method's 2nd parameter an object-based initial value which features two key-value pairs with the lookup
-key holding a Map
-reference and the result
-key referencing an array.
With each iteration the callback reducer function receives such an object as its first parameter. It also has to return such an object either with changes to its data or not. The very object's Map
reference will be used as one of the fastest possible ways of looking up whether a specific data has been already processed. The implementation would use a map's has
method on that behalf.
In case a data-item of interest has not yet been processed, one would set
an item specific entry at the very Map
-based lookup
. Additionally one would create a new, target-data specific object and push it into the result
-array.
The latter also features the final result at the reduce
task's return value.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const foodsList = [{
foodOrigin: "Padang", foodCode: "SPI", foodName: "Nasi Padang"
// and not ...
// // foodOrigin: "Padang", foodName: "Nasi Padang", originCode: "SPI",
}, {
foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN",
}, {
foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN",
}, {
foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG",
}, {
foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG",
}, {
foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT",
}];
const filteredFoodsList = foodsList
.reduce((collector, { foodOrigin, originCode = null }) => {
if (originCode !== null && !collector.lookup.has(foodOrigin)) {
collector.lookup.set(foodOrigin, true);
collector.result.push({
foodOrigin,
originCode,
});
}
return collector;
}, { lookup: new Map, result: [] }).result;
console.log({ filteredFoodsList });
<!-- language: lang-css -->
.as-console-wrapper { min-height: 100%!important; top: 0; }
<!-- end snippet -->
答案6
得分: 1
你可以像下面这样使用Array.reduce
:
const
foodsList = [ { foodOrigin: "Padang", foodName: "Nasi Padang", originCode: "PDN" }, { foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN" }, { foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN" }, { foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG" }, { foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG" }, { foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT" } ],
filteredFoodsList = foodsList.reduce(
(acc, {foodOrigin,originCode}) => acc.find(({originCode:oc}) => oc === originCode) ? acc : [...acc, {foodOrigin,originCode}], []
);
console.log( filteredFoodsList );
希望这对你有帮助。
英文:
You can use Array.reduce
as follows:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const
foodsList = [ { foodOrigin: "Padang", foodName: "Nasi Padang", originCode: "PDN" }, { foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN" }, { foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN" }, { foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG" }, { foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG" }, { foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT" } ],
filteredFoodsList = foodsList.reduce(
(acc, {foodOrigin,originCode}) => acc.find(({originCode:oc}) => oc === originCode) ? acc : [...acc, {foodOrigin,originCode}], []
);
console.log( filteredFoodsList );
<!-- end snippet -->
答案7
得分: 0
以下是翻译好的内容:
这可以通过从数组构造一个 Map
,然后获取其 values()
来更简单地完成。
const foodsList = [
{ foodOrigin: "Padang", foodName: "Nasi Padang", originCode: "PDN" },
{ foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN" },
{ foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN" },
{ foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG" },
{ foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG" },
{ foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT" }
];
const res = [...new Map(foodsList.map(({ foodOrigin, originCode }) =>
[originCode, { foodOrigin, originCode }]
)).values()];
console.log(res);
请注意,我只翻译了您提供的代码部分,没有包括其他内容。
英文:
This can done a lot more simply by constructing a Map
from an array, then taking its values()
.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const foodsList=[{foodOrigin:"Padang",foodName:"Nasi Padang",originCode:"PDN"},{foodOrigin:"Padang",foodName:"Gulai",originCode:"PDN"},{foodOrigin:"Padang",foodName:"Rendang",originCode:"PDN"},{foodOrigin:"Palembang",foodName:"Pempek",originCode:"PLG"},{foodOrigin:"Palembang",foodName:"Tekwan",originCode:"PLG"},{foodOrigin:"Yogyakarta",foodName:"Gudeg",originCode:"YKT"}];
const res = [...new Map(foodsList.map(({foodOrigin, originCode}) =>
[originCode, {foodOrigin, originCode}])).values()];
console.log(res);
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论