Создание объекта путем перебора двух массивов

Довольно просто.

Мне нужно создать функцию objOfMatches, которая принимает два массива и обратный вызов. objOfMatches создаст объект и вернет его. Чтобы построить объект, objOfMatches проверит каждый элемент первого массива, используя обратный вызов, чтобы увидеть, соответствует ли вывод соответствующему элементу (по индексу) второго массива. Если есть совпадение, элемент из первого массива становится ключом в объекте, а элемент из второго массива становится соответствующим значением.

function objOfMatches(array1, array2, callback) {
    //create obj
    var obj = {}

    //loop thru first array
    for(let i = 0; i < array1.length; i++) {
        for (let j = 0; j < array2.length; j++) {
            if (callback(array1[i]) === array2[j]) {                
                obj.array1[i] = array2[j];
            }
        }
    }
    return obj;
}

console.log(objOfMatches(['hi', 'howdy', 'bye', 'later', 'hello'], ['HI', 'Howdy', 'BYE', 'LATER', 'hello'], function(str) { return str.toUpperCase(); }));
// should log: { hi: 'HI', bye: 'BYE', later: 'LATER' }

Выглядит довольно просто, но я не совсем понимаю, почему он выдает TypeError в консоли. (TypeError: Cannot set property '0' of undefined)

Может кто-нибудь объяснить, что происходит?


person leonardofed    schedule 13.09.2018    source источник
comment
Попробуйте obj[array1[i]] = array2[j];.   -  person Ori Drori    schedule 13.09.2018
comment
@OriDrori хм, это работает. Звучит странно, но obj.array1[i] = array2[j]; не похоже на синтаксическую ошибку. Я был явно не прав.   -  person leonardofed    schedule 13.09.2018
comment
Это не так, но смысл не в том, что вы думаете. obj.array1[i] = array2[j] -> установить индекс i массива свойств obj в значение, а не устанавливать ключ по имени текста, который находится в индексе i в массиве.   -  person Ori Drori    schedule 13.09.2018
comment
это называется записью в скобках. Вы можете использовать его либо для доступа, либо для установки свойства объекта.   -  person oosniss    schedule 13.09.2018
comment
Почему 'hello' не является частью вашего ожидаемого результата?   -  person connexo    schedule 14.09.2018
comment
А почему howdy тоже нет в нем? Это совсем не довольно просто.   -  person connexo    schedule 14.09.2018
comment
@connexo видит обратный вызов, который передается в objOfMatches.   -  person leonardofed    schedule 14.09.2018
comment
Это всегда помогает обернуть длинные строки;) ... Соответственно скорректировал мой ответ.   -  person connexo    schedule 14.09.2018


Ответы (3)


Если вы хотите сопоставить соответствующие элементы, вам не нужно перебирать оба массива. Вы можете просмотреть один и использовать индекс, чтобы найти соответствующий объект в другом.

reduce() подходит для этого, потому что он позволит вам создать возвращаемый объект на месте и предоставит индекс текущей итерации цикла. Вы просто запускаете тест и назначаете ключ/значение, если тест верен.

function objOfMatches(arr1, arr2, callback){
  return arr1.reduce((obj, current, index) => {
    if(arr2[index] === callback(current)) obj[current] = arr2[index]
    return obj
  }, {})
}

console.log(objOfMatches(['hi', 'howdy', 'bye', 'later', 'hello'], ['HI', 'Howdy', 'BYE', 'LATER', 'hello'], function(str) { return str.toUpperCase(); }));

person Mark    schedule 13.09.2018
comment
красиво выразился Марк. - person leonardofed; 14.09.2018

Предполагая, что оба массива имеют одинаковую длину и индексы совпадающих элементов совпадают, очень простое сокращение приведет вас к этому:

const x = ['hi', 'howdy', 'bye', 'later', 'hello'],
      y = ['HI', 'Howdy', 'BYE', 'LATER', 'hello'];

console.log(x.reduce((a,v,i)=>Object.assign(a,{[v]:y[i]}),{}))

Если вам нужно проверить наличие и позицию совпадения, вам нужно изменить это, чтобы Array.prototype.reduce работало на вас:

const x = ['hi', 'later', 'howdy', 'bye', 'hello', 'foo'],
      y = ['HI', 'baz', 'Howdy', 'BYE', 'LATER', 'hello', 'bar'];

console.log(x.reduce((a,v)=> {
    let i = y.indexOf(v.toUpperCase())
    return i === -1 ? a : Object.assign(a, {[v]:y[i]})
  },{}
))

person connexo    schedule 13.09.2018

Следуя вашему подходу, вы должны использовать этот obj[array1[j]] = array2[i], вот пример:

function objOfMatches(array1, array2, callback) {
    //create obj
    var obj = {}

    //loop thru first array
    for(let i = 0; i < array1.length; i++) {
        for (let j = 0; j < array2.length; j++) {
            if (callback(array1[i]) === array2[j]) {   
                if(!array1[j] in obj) obj[array1[j]]  = [] 
                obj[array1[j]] = array2[i];
            }
        }
    }
    return obj;
}

console.log(objOfMatches(['hi', 'howdy', 'bye', 'later', 'hello'], ['HI', 'Howdy', 'BYE', 'LATER', 'hello'], function(str) { return str.toUpperCase(); }));

person Emeeus    schedule 13.09.2018
comment
Привет Emeeus, это решение довольно поучительно. Не могли бы вы подробнее объяснить вложенный оператор if? В частности, этот раздел: if(!array1[j] in obj) obj[array1[j]] = [] obj[array1[j]] = array2[i];. Спасибо - person Codestudio; 06.07.2020