Использование оператора распространения для расширения массива при использовании карты

Я не уверен, что это правильный подход, но мне любопытно, можно ли это сделать. У меня есть объект, из которого мне нужно создать массив, ключ - это элемент, а значение id - количество повторений в массиве.

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

Который должен сделать ['m','m','m','m','m','s','s' ... ]

Это рабочий подход:

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

Можно ли это сделать следующим образом:

var deck = Object.keys(streamDeck).map(function (agenda) {
  var partial = _.fill(Array(streamDeck[agenda]), agenda)
  return ...partial // I know this is wrong
})

3 ответа

Решение

Вы можете использовать распространение на Array.prototype.concatпостроить окончательный массив:

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>

ОБНОВИТЬ

Учитывая рекомендацию Берги, эта версия короче и не зависит от поведения Array.prototype в контексте массива:

const deck = [].concat(..._.map(arrayInstructions,
    (times,agenda) => _.times(times, _=>agenda)
));

Нет веской причины использовать оператор спреда здесь?

В простейшем виде оператор распространения позволяет вам использовать массив, в котором ожидаются несколько "элементов" или аргументов, например, что-то вроде

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

что кажется полезным, но вы заполняете массивы и соединяете их вместе и используете concat кажется более подходящим, однако вы можете ограничить это одним вызовом concat если вы используете apply и вернуть карту

"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>';

Как сказал Bergi, JS не имеет concatMap, но вы можете определить эту функциональность вручную:

function concatMap(array, func, thisArg) {
  return [].concat.apply([], [].map.call(array, func, thisArg));
}
concatMap(
  Object.keys(arrayInstructions),
  k => new Array(arrayInstructions[k]).fill(k)
);
Другие вопросы по тегам