0

I've got two arrays of strings of equal length, and I want to make a key:pair object out of them, like:

INPUT:

let words1 = ["foo", "loo", "who"];
let words2 = ["bar", "car", "mar"];

DESIRED OUTPUT:

{
  foo: "bar",
  loo: "car",
  who: "mar"
}

I originally accomplished this by doing:

const wordMap = {};
words1.map((word,n) => {
  wordMap[word] = words2[n];
})

However, our linter is throwing an error to "prefer destructuring". I can't seem to figure out how to do this using destructuring - and given that I'm pretty new to destructuring, I figure I must just be missing something. I'm struggling to find a clean way to do this... I figure the answer might resemble something like:

{[words1]:[...words2]};

Can't figure it out though. Here's a JSFiddle I was toying around with too. Let me know if there's a way to do this. Thanks!

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
Nate
  • 65
  • 1
  • 7
  • 1
    `map` returns an array so you shouldn't use it here. – Andy Aug 04 '22 at 19:09
  • 2
    perhaps you can do it with reduce – Daniel A. White Aug 04 '22 at 19:10
  • 2
    prefer destructuring shouldn't be flagging this code. it's complaining about `wordMap[word] = words2[n];` ? – Chris de Almeida Aug 04 '22 at 19:13
  • 3
    while u can achive the same thing using map this is not a good usecase. use map when u need to transform elements in an array to a new array of same length .use foreach instead of map – cmgchess Aug 04 '22 at 19:15
  • 1
    also mind telling what you are tryng to achive with `console.log(words1: {words2} )` – cmgchess Aug 04 '22 at 19:20
  • 1
    `words1.forEach((word, i) => wordMap[word] = words2[i]);`. – Andy Aug 04 '22 at 19:23
  • Here is a similar question [39127989](https://stackoverflow.com/questions/39127989/create-an-object-from-an-array-of-keys-and-an-array-of-values) – dreygur Aug 04 '22 at 19:29
  • @cmgchess Thanks for the tip on using map(), also the console.log was my attempt to create an object that matched my desired output using destructuring, instead of directly assigning it like in my original snippet with wordMap – Nate Aug 04 '22 at 19:32
  • @dreygur That question is somewhat similar, but in this instance my problem isn't achieving the results at all, rather it's accomplishing them while not setting off the linter's "prefer destructuring" flag – Nate Aug 04 '22 at 19:33
  • 1
    Strange, ESLint [simulation](https://eslint.org/play/#eyJ0ZXh0IjoiLyogZXNsaW50IHByZWZlci1kZXN0cnVjdHVyaW5nOiBcIndhcm5cIiAqL1xubGV0IHdvcmRzMSA9IFtcImZvb1wiLCBcImxvb1wiLCBcIndob1wiXTtcbmxldCB3b3JkczIgPSBbXCJiYXJcIiwgXCJjYXJcIiwgXCJtYXJcIl07XG5cbmNvbnN0IHdvcmRNYXAgPSB7fTtcbndvcmRzMS5tYXAoKHdvcmQsbikgPT4ge1xuICB3b3JkTWFwW3dvcmRdID0gd29yZHMyW25dO1xufSk7XG5cbmNvbnN0IHggPSB3b3JkczFbMF07XG4iLCJvcHRpb25zIjp7InBhcnNlck9wdGlvbnMiOnsiZWNtYVZlcnNpb24iOiJsYXRlc3QiLCJzb3VyY2VUeXBlIjoibW9kdWxlIiwiZWNtYUZlYXR1cmVzIjp7fX0sInJ1bGVzIjp7fSwiZW52Ijp7fX19) doesn't show this issue for your code. – n-- Aug 04 '22 at 20:39
  • @syduki really? I am seeing the use array destructuring message even in the simulation link you showed me: https://i.imgur.com/f21Fa1N.png That's a cool tool though, thanks for sharing it with me! – Nate Aug 04 '22 at 20:53
  • 1
    That is for my own code on line `10` which I added to be sure that rule is enforced. – n-- Aug 04 '22 at 20:56
  • 1
    @syduki https://eslint.org/play/#eyJ0ZXh0IjoiLyogZXNsaW50IHByZWZlci1kZXN0cnVjdHVyaW5nOiBbXCJ3YXJuXCIsIHtvYmplY3Q6IHRydWV9LCB7ZW5mb3JjZUZvclJlbmFtZWRQcm9wZXJ0aWVzOiB0cnVlfV0gKi9cbmxldCB3b3JkczEgPSBbXCJmb29cIiwgXCJsb29cIiwgXCJ3aG9cIl07XG5sZXQgd29yZHMyID0gW1wiYmFyXCIsIFwiY2FyXCIsIFwibWFyXCJdO1xuXG5jb25zdCB3b3JkTWFwID0ge307XG53b3JkczEubWFwKCh3b3JkLG4pID0+IHtcbiAgd29yZE1hcFt3b3JkXSA9IHdvcmRzMltuXTtcbn0pO1xuXG5jb25zdCB4ID0gd29yZHMxWzBdO1xuIiwib3B0aW9ucyI6eyJwYXJzZXJPcHRpb25zIjp7ImVjbWFWZXJzaW9uIjoibGF0ZXN0Iiwic291cmNlVHlwZSI6Im1vZHVsZSIsImVjbWFGZWF0dXJlcyI6e319LCJydWxlcyI6e30sImVudiI6e319fQ== – Bergi Aug 05 '22 at 01:59
  • 1
    @Nate Please [edit] your question to include your linter configuration (at least of the offending rule) – Bergi Aug 05 '22 at 02:10
  • @syduki I think you were right, the actual code I was working on looked like this: `forEach((row) => {/*...some code here ...*/ tMap[columnValues[0]] = [columnValues[2]];} ` Where I was parsing a HTML table, then taking the innerText from the first and third cells, and making key pairs out of them. For some reason reverting this somehow *doesn't* flag the linter anymore (use array destruct), and I'm quite confused (maybe it's due to changing map() to forEach here instead?). – Nate Aug 05 '22 at 14:43
  • @syduki Thanks either way, for my purposes I'm ok to just ignore the linting rule and move on with my life, it was a good catch though – Nate Aug 05 '22 at 14:43

5 Answers5

2

You could convert the words1 array to a combined words1/words2 array of arrays, which is perfect to run through Object.fromEntries.

let words1 = ["foo", "loo", "who"];
let words2 = ["bar", "car", "mar"];
const wordMap = Object.fromEntries(words1.map((w, i) => [w, words2[i]]));

console.log(wordMap);
James
  • 20,957
  • 5
  • 26
  • 41
1

As far as destructuring, you can reassign an object's keys with one array and the values with the other. LOOK MA! No iteration!:

let keys = ["foo", "loo", "who"];
let values = ["bar", "car", "mar"];

let zipped = {};

[zipped.foo, zipped.loo, zipped.who] = values;

console.log(zipped);

.reduce() and Object.assign(), the key is to pass the accumulator as the first parameter of Object.assign() and the value by index.

let keys = ["foo", "loo", "who"];
let values = ["bar", "car", "mar"];

const zipped = keys
.reduce((object, current, index) => 
  Object.assign(object, {[current]: values[index]}), {});

console.log(zipped);
zer00ne
  • 41,936
  • 6
  • 41
  • 68
1

Although James' solution works, it only works for ES2019 and after, because it uses .fromEntries(). If you use a predecessor, you might want to use the following (which uses destructuring):

const words1 = ['foo', 'loo', 'who'];
const words2 = ['bar', 'car', 'mar'];
const wordMap = Object.assign(...words1.map((k, i) => ({ [k]: words2[i] })));
console.log(wordMap);

If the first array has more words, it assigns undefined as its value (see below). If the second array has more words, it just creates N key/value pairs where N equals the length of the first array (basically stops after array 1 has no more words left).

const words1 = ['foo', 'loo', 'who', 'zoo'];
const words2 = ['bar', 'car', 'mar'];
const wordMap = Object.assign(...words1.map((k, i) => ({ [k]: words2[i] })));
console.log(wordMap);
Starfish
  • 3,344
  • 1
  • 19
  • 47
1

I can't seem to figure out how to do this using destructuring

The linter wants you to write

({[n]: wordMap[word]} = words2);

instead of

wordMap[word] = words2[n];

This is complete bullocks - less readable, more convoluted, and not even shorter than the simple and straightforward assignment. Ignore the rule here, it doesn't make sense - or disable it altogether, maybe at least the enforceForRenamedProperties option or the AssignmentExpression option.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I think this gets at the heart of my question the most. Destructuring as a whole, as well as the use of linting rules are newer concepts to me, so if the solution was that convoluted and not offering any guidance then that's the best take of it I think. Thanks a bunch! Bonus points to everyone else who noticed the snippet of code I included didn't actually flag the error, the code I had did, but it seems the reduced version I made here didn't. – Nate Aug 05 '22 at 14:38
-1

Use Object.hasOwnProperty, this will solve your problem.

let words1 = ["foo", "loo", "who"];
let words2 = ["bar", "car", "mar"];
let len = words1.length
let newObj = {}
for(let i=0; i<len; i++){
    if(!newObj.hasOwnProperty(words1[i])){
        newObj[words1[i]] = words2[i]
    }
}

console.log(newObj)
CijoDojo
  • 11
  • 1