#javascript #arrays #algorithm #csv #javascript-objects
Вопрос:
У меня есть данные, полученные из CSV-файла, которые могут содержать пустые поля и должны быть сгруппированы на основе этого.
Вот простой пример данных о лицах по местоположению. Данные о местоположении отображаются только для первого лица, и каждый следующий человек, которому не назначено местоположение, принадлежит местоположению, которое было указано ранее:
"Objects:", [{
location: "New York",
date: "10/10/2021",
name: "Max",
surname: "Payne"
}, {
location: "",
date: "",
name: "Duke",
surname: "Nuken"
}, {
location: "",
date: "",
name: "Jack",
surname: "Carver"
}, {
location: "Las Vegas",
date: "30/10/2021",
name: "Leon",
surname: "Kennedy"
}, {
location: "",
date: "",
name: "Donkey",
surname: "Kong"
}, {
location: "",
date: "",
name: "Ryu",
surname: "Hayabusa"
}]
Мне нужно объединить список людей в список и добавить его в соответствующее место:
"Objects:", [{
location: "New York",
date: "10/10/2021",
persons: [{
name: "Max",
surname: "Payne"
}, {
name: "Duke",
surname: "Nuken"
}, {
name: "Jack",
surname: "Carver"
}]
}, {
location: "Las Vegas",
date: "30/10/2021",
persons: [{
name: "Leon",
surname: "Kennedy"
}, {
name: "Donkey",
surname: "Kong"
}, {
name: "Ryu",
surname: "Hayabusa"
}]
}]
Данные первоначально поступают в виде массива массивов в этой форме:
const [headers, ...lines] = [
["location", "date", "name", "surname" ],
["New York", "10/10/2021", "Max", "Payne" ],
["", "", "Duke", "Nuken" ],
["", "", "Jack", "Carver" ],
["Las Vegas", "30/10/2021", "Leon", "Kennedy" ],
["", "", "Donkey", "Kong" ],
["", "", "Ryu", "Hayabusa"],
];
Код, который я в настоящее время должен преобразовать массив в первый список объектов в этом вопросе, таков:
const locations = lines.map( (line) =>
line.reduce((object, value, index) =>
({...object, [ headers[index] ]: value})
, {}
));
Каков был бы хороший способ решить эту проблему?
Ответ №1:
вот пример использования Array#reduce()
и жесткого кодирования имен заголовков.
const
[headers, ...lines] = [["location", "date", "name", "surname"], ["New York", "10/10/2021", "Max", "Payne"], ["", "", "Duke", "Nuken"], ["", "", "Jack", "Carver"], ["Las Vegas", "30/10/2021", "Leon", "Kennedy"], ["", "", "Donkey", "Kong"], ["", "", "Ryu", "Hayabusa"],],
result = lines.reduce((a, [location, date, name, surname]) => {
if (location amp;amp; date) a.push({ location, date, persons: [] });
a[a.length - 1].persons.push({ name, surname });
return a;
}, []);
console.log(JSON.stringify(result, null, 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Вот более динамичный пример, позволяющий указать «Требуемые объекты», которые должны присутствовать для группировки. Вы можете приспособиться к вашим конкретным потребностям.
const
input = [["location", "date", "name", "surname"], ["New York", "10/10/2021", "Max", "Payne"], ["", "", "Duke", "Nuken"], ["", "", "Jack", "Carver"], ["Las Vegas", "30/10/2021", "Leon", "Kennedy"], ["", "", "Donkey", "Kong"], ["", "", "Ryu", "Hayabusa"],],
refactorCSV = (arr, requiredIndeces) => {
const
reduceByRequiredIndex = (arr) => arr.reduce((a, x, i) =>
(a[ requiredIndeces.includes(i)].push(x), a), [[], []]),
[headers, ...lines] = arr,
[entryProps, requiredProps] = reduceByRequiredIndex(headers);
return lines.reduce((a, line) => {
const [personValues, requiredValues] = reduceByRequiredIndex(line);
if (requiredValues.every(v => v !== '')) {
const required = {};
requiredProps.forEach((prop, i) => required[prop] = requiredValues[i]);
a.push({ ...required, persons: [] });
}
const person = {};
entryProps.forEach((prop, i) => person[prop] = personValues[i]);
a[a.length - 1].persons.push(person);
return a;
}, []);
},
result = refactorCSV(input, [0, 1]);
console.log(JSON.stringify(result, null, 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Комментарии:
1. Это очень хорошо! К сожалению, в моем случае использования я считаю, что заголовки могут отличаться, например, у меня может быть дата рождения или возраст человека или другое поле в городе.