Собираем массив объектов 5/5


#1

Ффух, это было посложнее, но тоже сдалось =) пока что как вы понимаете лишь кривая реализация, жду оптимизаторов в комменты
upd: топик обновляется по мере посещения вдохновения

бенчмарк вариантов на 10000 повторов
function bench(f, times) {
  var d = new Date();
  for (var i = 0; i < times; i++) f(["name", "growth", "weight", "age"], [
    ["Пётр", "165", "70"],
    ["Василий", "170"],
    ["Светлана"],
    [, , , , , , , , ]
  ]);
  return new Date() - d;
}

const var1 = function(keysArray, arrayOfDataArrays) {
  let array = [];
  for (let i = 0; i < arrayOfDataArrays.length; i++) {
    let obj = {};
    for (let j = 0; j < keysArray.length; j++) {
      if (arrayOfDataArrays[i][j]) {
        obj[keysArray[j]] = arrayOfDataArrays[i][j];
      }
    }
    array.push(obj);
  }
  return array;
}
const var2 = function(keysArray, arrayOfDataArrays) {
  let arr = [];
  for (let i = 0; i < arrayOfDataArrays.length; i++) {
    arr[i] = {};
    for (let j = 0; j < keysArray.length && arrayOfDataArrays[i][j]; j++) {
      arr[i][keysArray[j]] = arrayOfDataArrays[i][j];
    }
  }
  return array;
}

const var3 = (keys, data) => data.map(item => item = keys.reduce(
  (acc, cur, i) => {
    item[i] ? acc[cur] = item[i] : null;
    return acc;
  }, {}));


function log(msg) {
  alert(msg);
}


log('var1: ' + bench(var1, 10000));
log('var2: ' + bench(var2, 10000));
log('var3: ' + bench(var3, 10000));
1 вариант - тут понятнее
const getData = function(keysArray, arrayOfDataArrays) {
  let array = [];
  for (let i = 0; i < arrayOfDataArrays.length; i++) {
    let obj = {};
    for (let j = 0; j < keysArray.length; j++) {
      if (arrayOfDataArrays[i][j]){
      obj[keysArray[j]] = arrayOfDataArrays[i][j];
      }
    }
    array.push(obj);
  }
  return array;
}
2 вариант - тут поменьше итераций
const getData = function(keysArray, arrayOfDataArrays) {
  let array = [];
  for (let i = 0; i < arrayOfDataArrays.length; i++) {
    let obj = {};
    for (let j = 0; j < keysArray.length && arrayOfDataArrays[i][j]; j++) {
      obj[keysArray[j]] = arrayOfDataArrays[i][j];
    }
    array.push(obj);
  }
  return array;
}
3 вариант - не поймешь - значит слабак
const getData = (keys, data) => data.map(item => item = keys.reduce(
  (acc, cur, i) => {
    item[i] ? acc[cur] = item[i] : null;
    return acc;
  }, {}));

#2

Спасибо за приведенное решение.

Расскажите, пожалуйста, как вы пришли к такому решению?

В частности, что проверяет эта:

if (arrayOfDataArrays[i][j]){
      obj[keysArray[j]] = arrayOfDataArrays[i][j];
      }

проверка и как она работает?


#3

Если вам не трудно, объясните, еще, пожалуйста, решение, что было приведено одним из комментаторов в задании. Вот решение:

var getData = function (keys, values) {
  var newArray = [];

  for (var i = 0; i <= values.length - 1; i++) {

    var newObject = {};
    
    if (values[i].length - 1 <= keys.length - 1) {
      var length = values[i].length - 1;
    } else {
      length = keys.length - 1
    }

    for (var j = 0; j <= length; j++) {
      newObject[keys[j]] = values[i][j];
    }
    
    newArray.push(newObject);
  }
  
  return newArray
};

В частности, что делает проверка:

 if (values[i].length - 1 <= keys.length - 1) {
          var length = values[i].length - 1;
        } else {
          length = keys.length - 1
        }

И как устроен цикл:

 for (var j = 0; j <= length; j++) {
          newObject[keys[j]] = values[i][j];
        }

— что он перебирает?


#4

тут будет тяжко =)

рассмотрим 1ую итерацию внешнего цикла, на которой рассматривается 1ый массив из “массива массивов”
условие: пока есть элементы в этом массиве, мы перебираем ключи (внутренним циклом-j) и каждому ключу присваиваем соответствующий элемент массива (1ый ключ - 1 элем. массива, 2ой ключ - 2 элем. массива и т.д., пока не кончатся элементы массива). Соответственно если у нас кончились ключи, мы не сможем создать свойство объекта без ключа и ограничение в количестве элементов массива тоже выполняется (как исходное условие). Когда объект полностью наполнился ключами, он добавляется в массив array последним элементом.

на второй итерации внешнего цикла-i создается 2ой объект и т.д.

про чалика:
внутренний цикл тот же, что и у меня, с той лишь разницей, что значение length у него переменное, а именно придуман костыль:
перебрать ключи либо до длины мелкого массива значений, либо перебрать ключи до длины массива ключей, смотря что из этого будет меньше. Решение такое я считаю неоптимальным по той причине, что массив может быть очень интересной длины: к примеру, он может быть длиной 9 элементов, а реально в нем будет 0 элементов. выглядит он так: [,,,,,,,,]
то есть, будет не пустой объект, а объект с ключами и неопределенными значениями. Странно, что разрабы курса не добавили такой нюанс в проверку =)
попробуйте вызвать функцию с моим кодом и его кодом вот так:

getData(["name","growth","weight","age"],
[["Пётр","165","70"],["Василий","170"],["Светлана"], [,,,,,,,,]]);

и поймете разницу, о которой речь


#5

Возьмем для примера такие аргументы:

  • keysArray (массив ключей) — [“sea”,“country”,“city”]
  • arrayOfDataArrays (массив значений) — [[“Балтийское”,“Эстония”,“Силламяэ”],[“Охотское”,“Россия”,“Охотск”],[“Жёлтое”,“Китай”,“Бэйдайхэ”]].

Если я правильно понял, то работает это так:

Есть 2 цикла: внешний —

for (let i = 0; i < arrayOfDataArrays.length; i++) {
}

и внутренний —

for (let j = 0; j < keysArray.length; j++) {
}

Внешним циклом перебираются массивы в массиве «arrayOfDataArrays», а именно:
1-ая итерация, когда i = 0 — выбирается массив значений [“Балтийское”,“Эстония”,“Силламяэ”], после чего начинает работать внутренний цикл — начинается перебор ключей из массива «keysArray», а именно: [“sea”,“country”,“city”], и, пока в массиве значений [“Балтийское”,“Эстония”,“Силламяэ”] есть элементы — за этот момент в коде отвечает вот этот участок:

if (arrayOfDataArrays[i][j])

— пока выполняется это условие (пока в массиве значений [“Балтийское”,“Эстония”,“Силламяэ”] есть элементы) мы присваиваем ключам [“sea”,“country”,“city”] значения из массива [“Балтийское”,“Эстония”,“Силламяэ”] и записываем формируемую коллекцию в объект:

obj[keysArray[j]] = arrayOfDataArrays[i][j];

Получается вот такой объект:

{“sea”:“Балтийское”,“country”:“Эстония”,“city”:“Силламяэ”}

После того, как элементы в массиве значений [“Балтийское”,“Эстония”,“Силламяэ”] заканчиваются сформированный объект записывается в массив:

array.push(obj);

На второй внешней итерации берется второй массив значений [“Охотское”,“Россия”,“Охотск”] и начинает работать внутренний цикл — начинается перебор ключей из массива «keysArray», а именно: [“sea”,“country”,“city”], и, пока в массиве значений [“Охотское”,“Россия”,“Охотск”] есть элементы — за этот момент в коде отвечает вот этот участок:

if (arrayOfDataArrays[i][j])

— пока выполняется это условие (пока в массиве значений [“Охотское”,“Россия”,“Охотск”] есть элементы) мы присваиваем ключам [“sea”,“country”,“city”] значения из массива [“Охотское”,“Россия”,“Охотск”] и записываем формируемую коллекцию в объект:

obj[keysArray[j]] = arrayOfDataArrays[i][j];

Получается вот такой объект:

{"sea":"Охотское","country":"Россия","city":"Охотск"}

И так далее.

Верно ли я описал логику работы вашего решения?


#6

да, верно. чекните, я там второй вариант добавил, в первом у меня внутренний цикл вхолостую работал немного


#7

Просьба подсказать по какой причине вылазит ошибка. Спасибо!


#8

valueArr[i][j].length эт чо? сами объяснить сможете?


#9

Спасибо, глупость с недосыпа написал, просьба админов удалить комент выше.


#10

@Hierumo Блин, я не могу понять почему у тебя работает правильно вот этот цикл:

for (let j = 0; j < keysArray.length && arrayOfDataArrays[i][j]; j++)

, а конкретно вот эта часть: arrayOfDataArrays[i][j]

Она же по сути возвращает каждый элемент массива c массивами, а не его длину! А нам ведь нужно что бы [j] - количество итераций текущего цикла не превышало длину массива keysArray и длину массива arrayOfDataArrays[i]


#11

нет, она ничего не “возвращает”, это проверка на существование элемента. если его нет, то нет смысла дальше пробегать по массиву ключей. собственно эта часть родилась из более простой версии скрипта, см. первый вариант. просто я его из тела цикла засунул в условие выхода


#12

Hierumo, сделал идентично первому варианту, только вместо array.push(obj) написал array[i] = obj.


#13
var getData = function(keys, dataArray) {
  var result = [];

  for (var i = 0; i < dataArray.length; i++) {
// Сначала определяем, сколько пар «ключ-значение» будет в объекте.
    var length = keys.length;
    if (dataArray[i].length < keys.length) {
      length = dataArray[i].length;
    }
// Затем, опираясь на полученное значение, собираем объект.    
    var someObject = {};
    for (var j = 0; j < length; j++) {
      someObject[keys[j]] = dataArray[i][j];
    }
// И добавляем его в итоговый массив.
    result.push(someObject);
  }
  
  return result
}

#15

Может кто сказать в чем ошибка? 2 из 3 проверок проходит. В той проверке которую не проходит ожидаемое совпадает с тем что по факту но все равно почему то считает за ошибку… Объясните а то я по ходу совсем тупенький

`var getData = function (keys, mass) {
var obj = [];

for (var i = 0; i < mass.length; i++) {
var swap = {};
for (var j = 0; j < keys.length; j++) {
swap[keys[j]] = mass[i][j];
}
obj[i] = swap;
}

return obj;
}

`


#16

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


#17

аа. понятненько. Благодарю)


#18
var getData = function (keys, values) {
  var obj = [];
  for (var i = 0; i < values.length; i++ ) {
    obj[i] = {}; 
     for (var j = 0; j < values[i].length && j < keys.length ; j++ ) {
     obj[i][keys[j]] = values[i][j];
    }
    }
  return obj;
  };

#19

а можете написать код с какими-то более продвинутыми функциями, которые мы не изучали? reduce sort filter? )


#21

не думаю, что это будет понятный вариант, но добавил вариант 3. Сделал с использованием функции из задания 3/5
ваш код имеет недочеты - переменную obj все же стоит назвать array или arr, это же массив. и еще такой момент, если в массиве данных придет массив с ненулевой длиной и undefined значениями, ваш код обработает его некорректно. т.е. заполнит объект ключами с undefined значениями. что я имею ввиду:
протестируйте вот этот вызов:

 console.log(getData(["name","growth","weight","age"],[["Пётр","165","70"],["Василий","170"],["Светлана"],[,,,,,,,,]]));

последним идет как раз тот самый коварный массив с ненулевой длиной и пустыми значениями.

поэтому не понял зачем нужно j < values[i].length , ведь мы должны проверять не на длину массива внутри массива, а на присутствие элемента


#22

Спасибо за поправку.
Уязвимость действительно жёсткая.
Но я тоже хочу внести поправку, я подправил свой код, и использовал даже Ваши решения, но в них тоже есть уязвимость. Создаётся пустой объект. Этого быть не должно. Давайте её решать как-то вместе:

Я предлагаю вот такое рабочее решение. Обратите внимание также на все условия выполнения циклов.

var getData = function (keys, values) {
  var arr = [];
  for (var i = 0; values[i] && values[i].reduce((a,b) => a + b,0); i++ ) {
    arr[i] = {}; 
     for (var j = 0; values[i][j] && keys[j] ; j++ ) {
     arr[i][keys[j]] = values[i][j];
    }
    }
  return arr;
  };

Но в случае если keys тоже состоит из пустых строк, то получим вот такой ответ:

Итоговое рабочее решение:

var getData = function (keys, values) {
  var arr = [];
 
  for (var i = 0; values[i] && keys.reduce((a,b) => a + b,0) && values[i].reduce((a,b) => a + b,0); i++ ) {
    arr[i] = {}; 
     for (var j = 0; values[i][j] && keys[j] ; j++ ) {
     arr[i][keys[j]] = values[i][j];
    }
    } 
  return arr;
  };

console.log(getData([,,,,,,,,],[["Пётр","165","70"],["Василий","170"],["Светлана"],[,,,,,,,,]]));