2016-05-10 18 views
14

Powiedzmy, że mam tablicę var arr = [1, 2, 3] i chcę oddzielić każdy element przez element np. var sep = "&", więc wynikiem jest [1, "&", 2, "&", 3].Traszki sposób na przeplatanie elementów między wszystkimi elementami tablicy JavaScript?

Innym sposobem, aby o tym pomyśleć, jest wykonanie Array.prototype.join (arr.join(sep)) bez wyniku będącego łańcuchem (ponieważ elementy i separator, których próbuję użyć, to Obiekty, a nie ciągi znaków).

Czy istnieje funkcjonalny/miła/elegancki sposób to zrobić albo w ES6/7 lub lodash bez czegoś, co czuje niezgrabne jak:

_.flatten(arr.map((el, i) => [el, i < arr.length-1 ? sep : null])) // too complex 

lub

_.flatten(arr.map(el => [el, sep]).slice(0,-1) // extra sep added, memory wasted 

lub nawet

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 

Edytuj: Haskell ma tę funkcję, nazywa się intersperse

Odpowiedz

12

Stosowanie prądnicy:

function *intersperse(a, delim) { 
    let first = true; 
    for (const x of a) { 
    if (!first) yield delim; 
    first = false; 
    yield x; 
    } 
} 

console.log([...intersperse(array, '&')]); 

Dzięki @Bergi za wskazanie przydatnych uogólnienie, że wejście może być żadnych iterable.

Jeśli nie lubisz używać generatorów, następnie

[].concat(...a.map(e => ['&', e])).slice(1) 
2

JavaScript sposób przyłączenia() i podzielone()

var arr = ['a','b','c','d']; 
arr = arr.join('&'); 
document.writeln(arr); 

wyjścia powinien być: & b & C & d

rozdzieliła się jeszcze:

arr = arr.split(""); 

ARR jest teraz:

arr = ['a','&','b','&','c','&','d']; 
+1

Jak już wspomniano powyżej, rodzimy dołączyć metoda nie działa, jak nie używam strun. Zaktualizuję pytanie innym przykładem. –

+0

Widzę twój punkt widzenia. – Bryan

+0

dodano nowe rozwiązanie poniżej. – Bryan

-1

Aktualizacja dla obiektów nie przyłączyć za pomocą metody:

for (var i=0;i<arr.length;i++;) { 
    newarr.push(arr[i]); 
    if(i>0) { 
     newarr.push('&'); 
    }  
} 

newarr powinno być:

newarr = ['a','&','b','&','c','&','d']; 
+0

TO odwraca kolejność elementów tablicy. –

+0

Przepraszam, poprawiono – Bryan

+0

Po pierwsze, generuje to błąd składni ze względu na dodatkowy średnik na końcu instrukcji 'for'. Po drugie, nie ma żadnych ampersand po pierwszym elemencie i dodatkowych ampersand na końcu. –

2

do smarowania pieczywa i wyraźny zwrot w funkcji redukującej sprawi, że będzie bardziej zwięzły:

const intersperse = (arr, sep) => arr.reduce((a,v)=>[...a,v,sep],[]).slice(0,-1) 
// intersperse([1,2,3], 'z') 
// [1, "z", 2, "z", 3] 
4

W ES6, można napisać funkcję generatora, który może wyprodukować iterator który daje wejście z przeplatanych elementów:

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], "&"))); 
+2

lub 'yield * [separator, wartość]' :-) –

+0

@torazaburo: Nigdy bym o tym nie pomyślał. Interesujące, ale tylko dobre do gry w golfa :-) – Bergi

3

Jedno proste podejście może być jak karmienie funkcję redukcji z początkowym tablicy w rozmiarze jeden mniej niż podwójna z naszej oryginalnej tablicy, wypełniona znakiem, który ma być używany do przeplatania. Następnie odwzorowanie elementów oryginalnej tablicy w indeksie i na 2 * i w początkowo zasilanej macierzy docelowej powinno wykonać to zadanie idealnie.

W tym podejściu nie widzę (m) żadnych zbędnych operacji. Ponieważ nie modyfikujemy żadnego z rozmiarów macierzy po ich ustawieniu, nie oczekiwałbym, że jakiekolwiek zadania w tle będą uruchamiane w celu realokacji pamięci, optymalizacji itp. Jedną z innych dobrych części jest stosowanie standardowych metod tablicowych, ponieważ sprawdzają one wszystkie rodzaje niedopasowanie i co.

Ta funkcja zwraca nową tablicę, w której wywołane elementy tablicy są przeplatane z podanym argumentem.

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

1

Korzystanie reduce ale bez 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; 
},[]); 
0

Jeśli masz Ramda w swoich zależnościach czy gotów go dodać, istnieje intersperse metoda istnieje.

Od docs:

Tworzy nową listę z separatora umieszczonego między elementami.

Wysłania do drugiej metody drugiego argumentu, jeśli jest obecny.

R.intersperse('n', ['ba', 'a', 'a']); //=> ['ba', 'n', 'a', 'n', 'a'] 

Albo można sprawdzić źródło dla jednego ze sposobów, aby to zrobić w swoim kodzie. https://github.com/ramda/ramda/blob/v0.24.1/src/intersperse.js

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

można również użyć następujących:

var arr =['a', 'b', 'c', 'd']; 
arr.forEach(function(element, index, array){ 
    array.splice(2*index+1, 0, '&'); 
}); 
arr.pop();