leonardofed
leonardofed

Reputation: 976

Building an object by looping thru two arrays

Pretty straightforward.

I need to construct a function objOfMatches that accepts two arrays and a callback. objOfMatches will build an object and return it. To build the object, objOfMatches will test each element of the first array using the callback to see if the output matches the corresponding element (by index) of the second array. If there is a match, the element from the first array becomes a key in an object, and the element from the second array becomes the corresponding value.

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' }

Looks quite simple, yet I'm not fully understanding why does it throw a TypeError in the console. (TypeError: Cannot set property '0' of undefined)

Can someone explain what's going on?

Upvotes: 0

Views: 421

Answers (3)

connexo
connexo

Reputation: 56754

Assuming both arrays are of equal lengths and the indexes of matching elements match, a very straightforward reduce gets you there:

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]}),{}))

If you need to check for the match existence and position, this is what you'd need to modify to make Array.prototype.reduce work for you:

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]})
  },{}
))

Upvotes: 1

Emeeus
Emeeus

Reputation: 5250

Following your approach, you should use this obj[array1[j]] = array2[i], here the example:

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(); }));

Upvotes: 0

Mark
Mark

Reputation: 92440

If you want to match corresponding elements you don't need to loop through both arrays. You can loop through one and use the index to find the corresponding object in the other.

reduce() is nice for this because it will let you build your return object in place and it provides the index of the current loop iteration. You just run the test and assign the key/value if the test is true.

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(); }));

Upvotes: 1

Related Questions