JS: обновить атрибут последнего добавленного элемента после того, как push () в цикле не назначит правильное значение - PullRequest
0 голосов
/ 04 июля 2019

У меня есть следующий код:

var nameData = [{id: "1", name: "George,Steve,Andy"},{id: "2", name: "Andy,Bradley"},{id: "3", name: "George"},{id: "4", name: "Joseph,Julia"}]
var newNames = []
for (var c=0; c<nameData.length; c++) { 
    //create an array of names
    var names = nameData[c].name.toString().split(",")

    //loop through the name array and for each name add a new entry in the newNames array
    for (var n=0; n<names.length; n++) {
            newNames.push(nameData[c])
            newNames[newNames.length-1].name = names[n]
    }                           
}

Мой вывод здесь следующий:

0: {id: "1", name: "Andy"}
1: {id: "1", name: "Andy"}
2: {id: "1", name: "Andy"}
3: {id: "2", name: "Bradley"}
4: {id: "2", name: "Bradley"}
5: {id: "3", name: "George"}
6: {id: "4", name: "Julia"}
7: {id: "4", name: "Julia"}

Однако, мой желаемый результат будет таким:

0: {id: "1", name: "George"}
1: {id: "1", name: "Steve"}
2: {id: "1", name: "Andy"}
3: {id: "2", name: "Andy"}
4: {id: "2", name: "Bradley"}
5: {id: "3", name: "George"}
6: {id: "4", name: "Joseph"}
7: {id: "4", name: "Julia"}

Что-то не так с назначением атрибута name в цикле. Все записи из одного id получают фамилию в атрибуте name. Почему это так и как получить желаемый результат?

Ответы [ 3 ]

1 голос
/ 04 июля 2019

Вы используете newNames.push(nameData[c]);, который передаст ссылку на объект.Вместо этого сначала клонируйте объект, а затем нажмите.

var nameData = [{id: "1", name: "George,Steve,Andy"},{id: "2", name: "Andy,Bradley"},{id: "3", name: "George"},{id: "4", name: "Joseph,Julia"}]
var newNames = []
for (var c=0; c<nameData.length; c++) { 
    //create an array of names
    var names = nameData[c].name.toString().split(",")

    //loop through the name array and for each name add a new entry in the newNames array
    for (var n=0; n<names.length; n++) {
            newNames.push(Object.assign({}, nameData[c]));
            newNames[newNames.length-1].name = names[n];
    }                           
}

console.log(newNames);

Вы также можете использовать reduce.

var nameData = [{id: "1", name: "George,Steve,Andy"},{id: "2", name: "Andy,Bradley"},{id: "3", name: "George"},{id: "4", name: "Joseph,Julia"}]

const output = nameData.reduce((accu, {id, name}) => {
    name.split(",").forEach((name) => accu.push({id, name}));
    return accu;    
}, []);

console.log(output);
0 голосов
/ 04 июля 2019

Хотя принят провайдером ответа точное объяснение. Тем не менее, я думаю, что причина, по которой вы столкнулись с этой проблемой, заключается не только реализация кода, но также дизайн кода.

Ваша реализация в low level abstraction, вы делаете это в обязательном порядке, поэтому вам нужно обрабатывать слишком много деталей, как loop control, mutate reference и так далее. Я предпочитаю рефакторинг в functional style.

const newNames = nameData.flatMap(data =>
  data.name.split(",").map(name => ({
    id: data.id,
    name
  }))
);

Я думаю, что вы хотите сделать, это: Квартира newData делится на name.

Итак, как вы можете видеть, приведенный выше пример просто flatMap it, и вам не нужно обрабатывать детали цикла.

Дальше больше, потому что map или flatMap является неизменяемой функцией стиля, и мы получаем новые данные копировать, но не изменять ссылку, нам не нужно заботиться ни о ссылках, ни об искажении исходных данных.

Совет: flatMap - это новая функция JS, позаботьтесь о совместимости.

0 голосов
/ 04 июля 2019

если вам нравятся сокращенные решения, вы можете:

nameData.reduce((a, { id, name: names }) => 
    a.concat(names.split(',').map(name => ({id, name})))
, [])
...