جاوااسکریپت - چگونه یک آرایه از اشیاء را با توجه به کلید گروهبندی کنیم وقتی اشیاء میتوانند انواع مختلف داشته باشند
من یک آرایه از اشیاء به این شکل دارم:
const input = [
{
"name" : "car",
"sign" : "+",
"options" : "benz"
},
{
"name" : "bike",
"sign" : "+",
"options" : "pulsar"
},
{
"name" : "bike",
"sign" : "+",
"options" : "enfield"
},
{
"name" : "car",
"sign" : "+",
"options" : ["toyota","hyundai","benz"]
},
{
"name" : "",
"sign" : "",
"options" : ""
},
{
"name" : "car",
"sign" : "+",
"options" : ["audi", "ford"]
}
]
ساختار ورودی اینگونه است: هر شیء دارای ۳ جفت کلید-مقدار است.
همهی آنها میتوانند خالی باشند
میتواند مقادیر معتبر داشته باشد:
الف. گزینهها میتوانند یک رشته باشند
ب. یا میتواند یک آرایه باشد
من نمیخواهم اشیایی با مقادیر "" (رشته خالی) به خروجی اضافه شوند، خروجی باید به این شکل باشد:
[
{"car" : [ "benz", "toyota","hyundai", "audi", "ford"]},
{"bike" : ["pulsar","enfield" ]}
]
جوابهای مختلف دیگر نشان نمیدهند که چگونه باید زمانی که مقدار شیء میتواند هم آرایه و هم رشته باشد، برخورد کرد، بنابراین من یک سوال جدید مینویسم.
من مطمئن نیستم که باید از reduce استفاده کنم یا map. هر کمکی بسیار قدردانی میشود، پیشاپیش از شما متشکرم.
پاسخ شماره ۱
این یک عملیات «گروهبندی» نسبتاً استاندارد است که بر اساس یک ویژگی گروهبندی میکند و ویژگی دیگری را در یک آرایه جمعآوری میکند.
برای اینکه هم رشتهها و هم آرایهها را پشتیبانی کنید، از concat() استفاده میکنید تا مقدار options را به تجمعکننده اضافه کنید. تابع concat یا مقادیر فردی و یا آرایهای از مقادیر را میپذیرد و آرایههای بعدی را در آرایه هدف صاف (flatten) میکند. برای جلوگیری از تکراریها میتوانید از Set استفاده کنید. قطعه کد زیر تنها در صورتی عناصر را به تجمعکننده اضافه میکند که هر دو name و options معتبر باشند.
const input = [
{ "name": "", "sign": "+", "options": "benz" }, // blank 'name' property
{ "name": "bike", "sign": "+", "options": "" }, // blank 'options' property
{ "name": "bike", "sign": "+", "options": "enfield" },
{ "name": "car", "sign": "+", "options": ["toyota", "hyundai"] },
{ "name": "car", "sign": "", "options": "ford" },
{ "name": "car", "sign": "+", "options": ["audi", "ford"] }]
const result = Object.values(
input.reduce((acc, { name, options }) => {
if (name && options) {
const category = (acc[name] || (acc[name] = { [name]: [] }));
category[name] = [...new Set(category[name].concat(options))];
}
return acc;
}, {}));
console.log(result).as-console-wrapper { max-height: 100% !important; top: 0; }بهطور متناوب، برای جلوگیری از ایجاد یک مجموعه جدید در هر تکرار، میتوانید مقادیر را در یک مجموعه جمعآوری کرده و سپس نتیجهی فراخوانی reduce() را نگاشت کنید و هر مجموعه را به یک آرایه تبدیل کنید.
const input = [
{ "name": "", "sign": "+", "options": "benz" }, // blank 'name' property
{ "name": "bike", "sign": "+", "options": "" }, // blank 'options' property
{ "name": "bike", "sign": "+", "options": "enfield" },
{ "name": "car", "sign": "+", "options": ["toyota", "hyundai"] },
{ "name": "car", "sign": "", "options": "ford" },
{ "name": "car", "sign": "+", "options": ["audi", "ford"] }]
const result = Object.entries(
input.reduce((acc, { name, options }) => {
if (name && options) {
acc[name] || (acc[name] = new Set);
[].concat(options).forEach(option => acc[name].add(option));
}
return acc;
}, {}))
.map(([name, options]) => ({ [name]: [...options] }));
console.log(result);.as-console-wrapper { max-height: 100% !important; top: 0; }از آنجایی که به نظر میرسد نمیتوانید از تکرارکنندههای ES6 استفاده کنید، این یک گزینه است که فقط با استفاده از Array#includes() بررسی میکند تا از تکراریها جلوگیری شود.
const input = [
{ "name": "", "sign": "+", "options": "benz" }, // blank 'name' property
{ "name": "bike", "sign": "+", "options": "" }, // blank 'options' property
{ "name": "bike", "sign": "+", "options": "enfield" },
{ "name": "car", "sign": "+", "options": ["toyota", "hyundai"] },
{ "name": "car", "sign": "", "options": "ford" },
{ "name": "car", "sign": "+", "options": ["audi", "ford"] }]
const result = Object.values(
input.reduce((acc, { name, options }) => {
if (name && options) {
const category = (acc[name] || (acc[name] = { [name]: [] }));
[].concat(options).forEach(option => {
if (!category[name].includes(option)) category[name].push(option)
});
}
return acc;
}, {}));
console.log(result);.as-console-wrapper { max-height: 100% !important; top: 0; }ES3
var input = [
{ "name": "", "sign": "+", "options": "benz" },
{ "name": "bike", "sign": "+", "options": "" },
{ "name": "bike", "sign": "+", "options": "enfield" },
{ "name": "car", "sign": "+", "options": ["toyota", "hyundai"] },
{ "name": "car", "sign": "", "options": "ford" },
{ "name": "car", "sign": "+", "options": ["audi", "ford"] }
];
var temp = {};
for (var i = 0; i < input.length; i++) {
var name_ = input[i].name;
var options_ = input[i].options;
if (name_ !== undefined && name_ !== "" && options_ !== undefined && options_ !== "") {
if (!temp.hasOwnProperty(name_)) {
temp[name_] = {};
temp[name_][name_] = [];
}
var options_ = [].concat(options_);
for (var j = 0; j < options_.length; j++) {
if (!temp[name_][name_].includes(options_[j])) {
temp[name_][name_].push(options_[j]);
}
}
}
}
var result = [];
for (var key_ in temp) {
if (temp.hasOwnProperty(key_)) {
result.push(temp[key_]);
}
}
console.log(result);.as-console-wrapper { max-height: 100% !important; top: 0; }پاسخ شماره ۲
شما میتوانید از تابع reduce استفاده کنید و شرایطی که میخواهید را اضافه کنید.
const input = [
{
"name": "car",
"sign": "+",
"options": "benz"
},
{
"name": "bike",
"sign": "+",
"options": "pulsar"
},
{
"name": "bike",
"sign": "+",
"options": "enfield"
},
{
"name": "bike",
"sign": "+",
"options": "enfield"
},
{
"name": "car",
"sign": "+",
"options": ["toyota", "hyundai"]
},
{
"name": "",
"sign": "",
"options": ""
},
{
"name": "car",
"sign": "+",
"options": ["audi", "ford"]
}
]
let grouped = input.reduce(function (r, a) {
if (a.name !== "") {
r[a.name] = r[a.name] || [];
if (Array.isArray(a.options)) {
r[a.name] = Array.from( new Set (r[a.name].concat(a.options)))
} else {
r[a.name].push(a.options)
r[a.name] = Array.from( new Set (r[a.name]));
}
}
return r;
}, {});
let mapped = Object.entries(grouped).map(([key, value])=>{return{[key]:value}})
console.log(mapped)