Тесный способ пересечения элемента между всеми элементами массива JavaScript?
Скажем, у меня есть массив var arr = [1, 2, 3]
, и я хочу разделить каждый элемент на элемент, например. var sep = "&"
, поэтому выход [1, "&", 2, "&", 3]
.
Еще один способ подумать о том, что я хочу сделать Array.prototype.join(arr.join(sep)
) без результата, являющегося строкой (потому что элементы и разделитель, которые я пытаюсь использовать, являются объектами, а не строками).
Есть ли функциональный/приятный/элегантный способ сделать это в es6/7 или lodash без чего-то, что кажется неуклюжим:
_.flatten(arr.map((el, i) => [el, i < arr.length-1 ? sep : null])) // too complex
или
_.flatten(arr.map(el => [el, sep]).slice(0,-1) // extra sep added, memory wasted
или даже
arr.reduce((prev,curr) => { prev.push(curr, sep); return prev; }, []).slice(0,-1)
// probably the best out of the three, but I have to do a map already
// and I still have the same problem as the previous two - either
// inline ternary or slice
Изменить: Haskell имеет эту функцию, называемую intersperse
Ответы
Ответ 1
Использование генератора:
function *intersperse(a, delim) {
let first = true;
for (const x of a) {
if (!first) yield delim;
first = false;
yield x;
}
}
console.log([...intersperse(array, '&')]);
Благодаря @Bergi для указания полезного обобщения, что вход может быть любым итерабельным.
Если вам не нравятся использование генераторов, то
[].concat(...a.map(e => ['&', e])).slice(1)
Ответ 2
Распространение и явное возвращение в сокращающую функцию сделает его более кратким:
const intersperse = (arr, sep) => arr.reduce((a,v)=>[...a,v,sep],[]).slice(0,-1)
// intersperse([1,2,3], 'z')
// [1, "z", 2, "z", 3]
Ответ 3
В ES6 вы должны написать генераторную функцию, которая может создавать итератор, который дает вход с вкрапленными элементами:
function* intersperse(iterable, separator) {
const iterator = iterable[Symbol.iterator]();
const first = iterator.next();
if (first.done) return;
else yield first.value;
for (const value of iterator) {
yield separator;
yield value;
}
}
console.log(Array.from(intersperse([1, 2, 3], "&")));
Ответ 4
Один простой подход может быть похож на подачу функции уменьшения с начальным массивом размером один меньше, чем двойной из нашего исходного массива, заполненный символом, который будет использоваться для перемешивания. Тогда отображение элементов исходного массива с индексом я в 2 * я в исходном массиве целевых массивов выполнило бы работу отлично.
В этом подходе я не вижу (m) каких-либо избыточных операций. Кроме того, поскольку мы не изменяем размеры массива после их установки, я бы не ожидал выполнения каких-либо фоновых задач для перераспределения памяти, оптимизации и т.д.
Еще одна хорошая часть - использование стандартных методов массивов, поскольку они проверяют все виды несоответствий и многое другое.
Эта функция возвращает новый массив, в котором элементы вызываемого объекта массива вставляются с предоставленным аргументом.
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
Array.prototype.intersperse = function(s){
return this.reduce((p,c,i) => (p[2*i]=c,p), new Array(2*this.length-1).fill(s));
}
document.write("<pre>" + JSON.stringify(arr.intersperse("&")) + "</pre>");
Ответ 5
javascript имеет метод join() и split()
var arr = ['a','b','c','d'];
arr = arr.join('&');
document.writeln(arr);
Выход должен быть: a & c & d
теперь снова разделяется:
arr = arr.split("");
arr теперь:
arr = ['a','&','b','&','c','&','d'];
Ответ 6
Использование reduce
, но без slice
var arr = ['a','b','c','d'];
var lastIndex = arr.length-1;
arr.reduce((res,x,index)=>{
res.push(x);
if(lastIndex !== index)
res.push('&');
return res;
},[]);
Ответ 7
Если у вас Ramda в ваших зависимостях или если вы хотите добавить его, то intersperse
.
Из документов:
Создает новый список с разделителем между элементами.
Отправляется к второстепенному методу второго аргумента, если присутствует.
R.intersperse('n', ['ba', 'a', 'a']); //=> ['ba', 'n', 'a', 'n', 'a']
Или вы можете проверить источник для одного из способов сделать это в своей кодовой базе. https://github.com/ramda/ramda/blob/v0.24.1/src/intersperse.js
Ответ 8
if (!Array.prototype.intersperse) {
Object.defineProperty(Array.prototype, 'intersperse', {
value: function(something) {
if (this === null) {
throw new TypeError( 'Array.prototype.intersperse ' +
'called on null or undefined' );
}
var isFunc = (typeof something == 'function')
return this.concat.apply([],
this.map(function(e,i) {
return i ? [isFunc ? something(this[i-1]) : something, e] : [e] }.bind(this)))
}
});
}
Ответ 9
вы также можете использовать следующее:
var arr =['a', 'b', 'c', 'd'];
arr.forEach(function(element, index, array){
array.splice(2*index+1, 0, '&');
});
arr.pop();
Ответ 10
Мой дубль:
const _ = require('lodash');
_.mixin({
intersperse(array, sep) {
return _(array)
.flatMap(x => [x, sep])
.take(2 * array.length - 1)
.value();
},
});
// _.intersperse(["a", "b", "c"], "-")
// > ["a", "-", "b", "-", "c"]
Ответ 11
const arr = [1, 2, 3];
function intersperse(items, separator) {
const result = items.reduce(
(res, el) => [...res, el, separator], []);
result.pop();
return result;
}
console.log(intersperse(arr, '&'));
Ответ 12
Обновлен для объектов, не использующих метод соединения:
for (var i=0;i<arr.length;i++;) {
newarr.push(arr[i]);
if(i>0) {
newarr.push('&');
}
}
newarr должен быть:
newarr = ['a','&','b','&','c','&','d'];