Mam tablicę JavaScript, taką jak:
[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
Jak miałbym przejść do scalania oddzielnych wewnętrznych tablic w jeden taki jak:
["$6", "$12", "$25", ...]
javascript
arrays
flatten
Andy
źródło
źródło
reduce
+,concat
to O ((N ^ 2) / 2), gdzie jako zaakceptowana odpowiedź (tylko jedno wywołanie doconcat
) byłoby co najwyżej O (N * 2) w złej przeglądarce i O (N) w dobry. Również rozwiązanie Denys jest zoptymalizowane pod kątem rzeczywistego pytania i do 2x szybsze niż singielconcat
. Dlareduce
ludzi fajnie jest czuć się fajnie pisząc mały kod, ale na przykład, jeśli tablica zawiera 1000 jednoelementowych podrzędnych układów, wszystkie rozwiązania redukujące i konkatujące wykonałyby 500500 operacji, podczas gdy jako pojedyncza konkat lub prosta pętla wykonałaby 1000 operacji.[].concat(...array)
array.flat(Infinity)
gdzieInfinity
jest maksymalna głębokość do spłaszczenia.Odpowiedzi:
Możesz użyć
concat
do scalenia tablic:Użycie
apply
metodyconcat
spowoduje pobranie drugiego parametru jako tablicy, więc ostatni wiersz jest identyczny z tym:Istnieje również
Array.prototype.flat()
metoda (wprowadzona w ES2019), której można użyć do spłaszczenia tablic, chociaż jest ona dostępna tylko w Node.js od wersji 11, a wcale nie w Internet Explorerze .źródło
concat
nie modyfikuje tablicy źródłowej, więcmerged
tablica pozostanie pusta po wywołaniuconcat
. Lepiej powiedzieć coś takiego:merged = merged.concat.apply(merged, arrays);
var merged = [].concat.apply([], arrays);
wydaje się działać dobrze, aby uzyskać go w jednej linii. edycja: jak pokazuje odpowiedź Nikity.Array.prototype.concat.apply([], arrays)
.var merged = [].concat(...arrays)
Oto krótka funkcja, która wykorzystuje niektóre z nowszych metod tablic JavaScript do spłaszczenia n-wymiarowej tablicy.
Stosowanie:
źródło
flat
pierwszego wywołania przekazanej funkcji anonimowejreduce
. Jeśli nie zostanie określony, pierwsze wywołaniereduce
wiązania pierwszej wartości z tablicy doflat
, co ostatecznie spowoduje1
powiązanieflat
w obu przykładach.1.concat
nie jest funkcją.const flatten = (arr) => arr.reduce((flat, next) => flat.concat(next), []);
const flatten = (arr) => arr.reduce((flat, next) => flat.concat(Array.isArray(next) ? flatten(next) : next), []);
Istnieje myląco ukryta metoda, która konstruuje nową tablicę bez mutowania oryginalnej:
źródło
[].concat([[1],[2,3],[4]]...)
[[1],[2,3],[4]]
. Rozwiązanie podane przez @Nikita jest poprawne zarówno dla CoffeeScript, jak i JS.[].concat([1],[2,3],[4],...)
....
to rzeczywisty kod, a nie niektóre kropki elipsy.Najlepiej można to zrobić za pomocą funkcji redukcji javascript.
Lub z ES2015:
js-skrzypce
Dokumenty Mozilli
źródło
[]
i nie są wymagane żadne dalsze sprawdzenia.arrays.reduce((flatten, arr) => [...flatten, ...arr])
Istnieje nowa natywna metoda o nazwie flat, która dokładnie to robi.
(Pod koniec 2019 r.
flat
Jest teraz publikowany w standardzie ECMA 2019 icore-js@3
(biblioteka Babel) włącza go do swojej biblioteki wielopełniaczowej )źródło
Większość odpowiedzi tutaj nie działa na ogromnych tablicach (np. 200 000 elementów), a nawet jeśli tak, są one powolne. Odpowiedź polkovnikov.ph ma najlepszą wydajność, ale nie działa w przypadku głębokiego spłaszczania.
Oto najszybsze rozwiązanie, które działa również na tablicach z wieloma poziomami zagnieżdżenia :
Przykłady
Ogromne tablice
Świetnie radzi sobie z dużymi tablicami. Na mojej maszynie wykonanie tego kodu zajmuje około 14 ms.
Zagnieżdżone tablice
Działa z zagnieżdżonymi tablicami. Ten kod tworzy
[1, 1, 1, 1, 1, 1, 1, 1]
.Tablice o różnych poziomach zagnieżdżenia
Nie ma żadnych problemów z takimi spłaszczonymi tablicami.
źródło
RangeError: Maximum call stack size exceeded
). Dla 20 000 elementów matryca zajmuje 2-5 milisekund.Aktualizacja: okazało się, że to rozwiązanie nie działa z dużymi tablicami. Jeśli szukasz lepszego, szybszego rozwiązania, sprawdź tę odpowiedź .
Po prostu rozwija się
arr
i przekazuje jako argumentyconcat()
, które łączą wszystkie tablice w jedno. Jest to równoważne z[].concat.apply([], arr)
.Możesz także wypróbować to dla głębokiego spłaszczenia:
Zobacz demo na JSBin .
Odniesienia do elementów ECMAScript 6 zastosowanych w tej odpowiedzi:
Uwaga dodatkowa: metody takie jak
find()
i funkcje strzałek nie są obsługiwane przez wszystkie przeglądarki, ale to nie znaczy, że nie możesz teraz korzystać z tych funkcji. Wystarczy użyć Babel - przekształca kod ES6 w ES5.źródło
apply
w ten sposób, usunąłem moje komentarze z twoich. Nadal uważam, że używanieapply
/ rozpowszechnianie w ten sposób jest złe, ale ponieważ nikogo to nie obchodzi ...const flatten = arr => [].concat(...arr)
Możesz użyć podkreślenia :
źródło
true
drugi argument .Ogólne procedury oznaczają, że nie musimy przepisywać złożoności za każdym razem, gdy musimy zastosować określone zachowanie.
concatMap
(lubflatMap
) jest dokładnie tym, czego potrzebujemy w tej sytuacji.dalekowzroczność
I tak, zgadłeś poprawnie, spłaszcza tylko jeden poziom, dokładnie tak, jak powinno działać
Wyobraź sobie taki zestaw danych
Ok, teraz powiedzmy, że chcemy wydrukować listę pokazującą wszystkich graczy, którzy wezmą udział w
game
…Gdyby nasza
flatten
procedura spłaszczyła również zagnieżdżone tablice, otrzymalibyśmy ten wynik śmieci…tarzać się głęboko, kochanie
Nie oznacza to, że czasami nie chcesz spłaszczać również zagnieżdżonych tablic - tylko takie zachowanie nie powinno być domyślne.
Z
deepFlatten
łatwością możemy wykonać procedurę…Tam. Teraz masz narzędzie do każdego zadania - jedno do zgniatania jednego poziomu zagnieżdżenia
flatten
i jedno do niszczenia całego zagnieżdżaniadeepFlatten
.Może możesz to nazwać
obliterate
lubnuke
jeśli nie podoba ci się to imiędeepFlatten
.Nie powtarzaj dwa razy!
Oczywiście powyższe implementacje są sprytne i zwięzłe, ale przy użyciu
.map
wezwania do.reduce
oznacza, że faktycznie wykonujemy więcej iteracji niż to konieczneUżywanie sprawdzonego kombinatora, do którego dzwonię,
mapReduce
pomaga utrzymać iteracje na minimalnym poziomie; przyjmuje funkcję mapowaniam :: a -> b
, funkcję redukującąr :: (b,a) ->b
i zwraca nową funkcję redukującą - ten kombinator jest sercem przetworników ; jeśli jesteś zainteresowany, napisałem o nich inne odpowiedziźródło
concat
sam nie wysadza stosu, tylko...
iapply
robi (wraz z bardzo dużymi tablicami). Nie widziałem tego Po prostu czuję się teraz okropnie.concat
w Javascript ma inne znaczenie niż w Haskell. Haskell'sconcat
([[a]] -> [a]
) byłby wywoływanyflatten
w JavaScript i jest implementowany jakofoldr (++) []
(JavaScript:foldr(concat) ([])
przyjmowanie funkcji curry). JavaScriptconcat
jest dziwnym dodatkiem ((++)
w języku Haskell), który obsługuje zarówno[a] -> [a] -> [a]
ia -> [a] -> [a]
.flatMap
, ponieważ właśnie takconcatMap
jest:bind
Instancjalist
monady.concatpMap
jest implementowany jakofoldr ((++) . f) []
. Przetłumaczone na język JavaScript:const flatMap = f => foldr(comp(concat) (f)) ([])
. Jest to oczywiście podobne do twojej implementacji bezcomp
.Rozwiązanie dla bardziej ogólnego przypadku, gdy w tablicy mogą znajdować się elementy inne niż macierzowe.
źródło
Object.defineProperty(Array.prototype,'flatten',{value:function(r){for(var a=this,i=0,r=r||[];i<a.length;++i)if(a[i]!=null)a[i] instanceof Array?a[i].flatten(r):r.push(a[i]);return r}});
flattenArrayOfArrays (arr, 10)
lub tegoflattenArrayOfArrays(arr, [1,[3]]);
- te drugie argumenty zostaną dodane do wyniku.r
faktycznie połączy wyniki rekurencji.Co z użyciem
reduce(callback[, initialValue])
metodyJavaScript 1.8
Zrobiłbym robotę.
źródło
[[1], [2,3]].reduce( (a,b) => a.concat(b), [] )
jest bardziej seksowny.[[1], [2,3]].reduce( (a,b) => a.concat(b))
Kolejne rozwiązanie ECMAScript 6 w funkcjonalnym stylu:
Zadeklaruj funkcję:
i użyj go:
Rozważ także natywną funkcję Array.prototype.flat () (propozycja dla ES6) dostępną w ostatnich wydaniach współczesnych przeglądarek. Dzięki @ (Константин Ван) i @ (Mark Amery) wspomnieli o tym w komentarzach.
flat
Funkcja posiada jeden parametr określający oczekiwanej głębokości zagnieżdżenia tablicy, co równa się1
domyślnie.źródło
RangeError: Maximum call stack size exceeded
Aby spłaszczyć tablicę tablic jednoelementowych, nie trzeba importować biblioteki, prosta pętla jest jednocześnie najprostszym i najbardziej wydajnym rozwiązaniem:
Do downvoters: przeczytaj pytanie, nie głosuj downvote, ponieważ to nie pasuje do twojego zupełnie innego problemu. To rozwiązanie jest zarówno najszybsze, jak i najprostsze dla zadanego pytania.
źródło
['foo', ['bar']]
do['f', 'bar']
.źródło
Uwaga: kiedy
Function.prototype.apply
([].concat.apply([], arrays)
) lub operator rozkładania ([].concat(...arrays)
) jest używany do spłaszczenia tablicy, oba mogą powodować przepełnienie stosu dla dużych tablic, ponieważ każdy argument funkcji jest przechowywany na stosie.Oto bezpieczna implementacja w stosie w funkcjonalnym stylu, która porównuje najważniejsze wymagania względem siebie:
Gdy tylko przyzwyczaisz się do funkcji małych strzałek w formie curry, kompozycji funkcji i funkcji wyższego rzędu, kod ten brzmi jak proza. Programowanie polega zatem jedynie na złożeniu małych elementów, które zawsze działają zgodnie z oczekiwaniami, ponieważ nie zawierają żadnych skutków ubocznych.
źródło
const flatten = (arr) => arr.reduce((a, b) => a.concat(b), []);
oszczędza wizualne śmieci i wyjaśnia członkom drużyny, dlaczego potrzebujesz 3 dodatkowych funkcji i niektórych wywołań funkcji.ES6 One Line Spłaszcz
Zobacz lodash spłaszczony , podkreślenie spłaszczony (płytki
true
)lub
Testowane z
ES6 One Line Deep Flatten
Zobacz lodash flattenDeep , podkreślenie spłaszcz
Testowane z
źródło
Array.prototype.concat.apply([], arr)
ponieważ tworzysz dodatkową tablicę, aby dostać się doconcat
funkcji. Środowiska wykonawcze mogą go zoptymalizować, ale nie muszą go optymalizować po uruchomieniu, ale dostęp do funkcji w prototypie nie wygląda na bardziej brzydkiego, niż jest to w każdym przypadku.Możesz używać
Array.flat()
zInfinity
dowolną głębokością zagnieżdżonej tablicy.sprawdź tutaj zgodność przeglądarki
źródło
Podejście Haskellesque
źródło
Sposób ES6:
Sposób ES5 dla
flatten
funkcji z rezerwą ES3 dla tablic zagnieżdżonych w liczbie N:źródło
Jeśli masz tylko tablice z 1 elementem łańcuchowym:
wykona robotę. Bt, który konkretnie pasuje do Twojego przykładu kodu.
źródło
['$4', ["$6"], ["$12"], ["$25"], ["$25", "$33", ['$45']]].join(',').split(',')
[1,4, [45, 't', ['e3', 6]]].toString().split(',')
---- lub -----[1,4, [45, 't', ['e3', 6], false]].toString().split(',')
(Piszę to tylko jako osobną odpowiedź na podstawie komentarza @danhbear.)
źródło
Polecam funkcję generatora zajmującego mało miejsca :
W razie potrzeby utwórz tablicę spłaszczonych wartości w następujący sposób:
źródło
...
do iteracji przez generator.Wolałbym przekształcić całą tablicę taką, jaka jest, w ciąg znaków, ale w przeciwieństwie do innych odpowiedzi, zrobiłbym to przy użyciu,
JSON.stringify
a nie przy użyciutoString()
metody, która daje niepożądany wynik.Przy tym
JSON.stringify
wyjściu pozostaje tylko usunięcie wszystkich nawiasów, zawinięcie wyniku w nawiasy początkowe i końcowe i podanie wyniku, dziękiJSON.parse
któremu ciąg znaków powraca do „życia”.źródło
["345", "2", "3,4", "2"]
zamiast oddzielania każdej z tych wartości w celu oddzielenia indeksów"3,4"
.Możesz także wypróbować nową
Array.Flat()
metodę. Działa w następujący sposób:The
flat()
Sposób tworzy się nową tablicę ze wszystkimi elementami macierzy sub-łączonych do niego rekurencyjnie do 1 warstwy na głębokość (tzn tablice wewnątrz macierzy)Jeśli chcesz również spłaszczyć macierze trójwymiarowe lub nawet o wyższych wymiarach, wystarczy wywołać metodę płaską wiele razy. Na przykład (3 wymiary):
Bądź ostrożny!
Array.Flat()
metoda jest stosunkowo nowa. Starsze przeglądarki takie jak np. Mogły nie wdrożyć tej metody. Jeśli chcesz, aby kod działał we wszystkich przeglądarkach, może być konieczne przeniesienie JS do starszej wersji. Sprawdź dokumenty MD dotyczące bieżącej zgodności przeglądarki.źródło
Infinity
argumentem. W ten sposób:arr.flat(Infinity)
Za pomocą operatora rozprzestrzeniania:
źródło
To nie jest trudne, po prostu powtarzaj tablice i łącz je:
źródło
Wygląda na to, że wygląda to na REKURS!
Kod:
Stosowanie:
źródło
flatten(new Array(15000).fill([1]))
rzucaUncaught RangeError: Maximum call stack size exceeded
i zamraża moje devTools na 10 sekundZrobiłem to za pomocą rekurencji i zamknięć
źródło
Pewnego dnia wygłupiałem się z Generatorami ES6 i napisałem tę treść . Który zawiera...
Zasadniczo tworzę generator, który zapętla oryginalną tablicę wejściową, jeśli znajdzie tablicę, używa operatora fed * w połączeniu z rekurencją w celu ciągłego spłaszczania wewnętrznych tablic. Jeśli element nie jest tablicą, po prostu daje pojedynczy element. Następnie za pomocą operatora Spread ES6 (aka splat operator) spłaszczam generator w nowej instancji tablicy.
Nie przetestowałem wydajności tego, ale wydaje mi się, że jest to ładny prosty przykład użycia generatorów i operatora fed *.
Ale znowu, po prostu wygłupiałem się, więc jestem pewien, że są bardziej wydajne sposoby, aby to zrobić.
źródło
tylko najlepsze rozwiązanie bez lodash
źródło