5

I'm not sure if this is a correct approach, but I'm curious if it can be done. I have an object from which I need to create an array, the key is the item, and the value id the number of times it repeats in the array.

const arrayInstructions = {
  'm': 5,
  's': 5,
  'p': 5
}

Which should make ['m','m','m','m','m','s','s' ... ]

This is the working approach:

var array = []
Object.keys(arrayInstructions).forEach(function (agenda) {
  array = array.concat( _.fill(Array(arrayInstructions[agenda]), agenda) )
})

Can it be done in this manner:

var deck = Object.keys(streamDeck).map(function (agenda) {
  var partial = _.fill(Array(streamDeck[agenda]), agenda)
  return ...partial // I know this is wrong
})
2
  • 1
    No, it can't. You are looking for concatMap (which JS doesn't have). Commented Feb 29, 2016 at 17:37
  • Consider Object.keys(obj).reduce((s,k) => s+k.repeat(obj[k]), '').split(''). It does useless string concatenations, but it's short. Commented Feb 29, 2016 at 18:11

3 Answers 3

3

You could use spread on Array.prototype.concat to build the final array:

const arrayInstructions = { 'm': 5, 's': 5, 'p': 5 };

// This works because Array.prototype behaves like an empty list here
const deck = Array.prototype.concat(
  ..._.map(arrayInstructions, (times,agenda) => _.times(times, _=>agenda)) 
);

log(JSON.stringify(deck));

function log(x) { document.getElementsByTagName('pre')[0].appendChild(document.createTextNode(x)); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.5.1/lodash.js"></script>
<pre></pre>

UPDATE

Considering Bergi's recommendation, this version is shorter and does not rely on the behaviour of Array.prototype in array context:

const deck = [].concat(..._.map(arrayInstructions,
    (times,agenda) => _.times(times, _=>agenda)
));
Sign up to request clarification or add additional context in comments.

3 Comments

I would recomment [].concat(... …) though
@Bergi I was considering that as well, somehow [].concat(...x) feels more robust. Do you know any concrete scenarios where Array.prototype.concat(...x) wouldn't work?
Array.prototype[0] = "gotcha" would be disastrous :-) Admittedly it's a bit contrived, but could happen if someone uses Array.prototype.push(…) in a similar manner
2

There's no good reason to use a spread operator here?

In it's simplest form, the spread operator lets you use an array where multiple "elements" or arguments are expected, for your example something like

var part = [2, 3];
var arr  = [1, ...part, 4]; // [1,2,3,4]

which does seem useful, but you're filling arrays and joining them together, and using concat seems more appropriate, however you can limit this to one single call to concat if you use apply and return a map

"use strict"

const arrayInstructions = {
  'm': 5,
  's': 1,
  'p': 2
}

var deck = [].concat.apply([], Object.keys(arrayInstructions).map(function(k) { 
    return new Array(arrayInstructions[k]).fill(k) 
}));


//output
document.body.innerHTML = '<pre>' + JSON.stringify(deck, 0, 4) + '</pre>';

Comments

0

As Bergi said JS does not have concatMap, but you can define this functionality manually:

function concatMap(array, func, thisArg) {
  return [].concat.apply([], [].map.call(array, func, thisArg));
}
concatMap(
  Object.keys(arrayInstructions),
  k => new Array(arrayInstructions[k]).fill(k)
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.