Een array van arrays samenvoegen/afvlakken

Ik heb een JavaScript-array zoals:

[["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]

Hoe zou ik de afzonderlijke binnenste arrays kunnen samenvoegen tot één, zoals:

["$6", "$12", "$25", ...]

Antwoord 1, autoriteit 100%

U kunt concatgebruiken om arrays samen te voegen:

var arrays = [
  ["$6"],
  ["$12"],
  ["$25"],
  ["$25"],
  ["$18"],
  ["$22"],
  ["$10"]
];
var merged = [].concat.apply([], arrays);
console.log(merged);

Antwoord 2, autoriteit 25%

Hier is een korte functie die enkele van de nieuwere JavaScript-arraymethoden gebruikt om een n-dimensionale array af te vlakken.

function flatten(arr) {
  return arr.reduce(function (flat, toFlatten) {
    return flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten);
  }, []);
}

Gebruik:

flatten([[1, 2, 3], [4, 5]]); // [1, 2, 3, 4, 5]
flatten([[[1, [1.1]], 2, 3], [4, 5]]); // [1, 1.1, 2, 3, 4, 5]

Antwoord 3, autoriteit 15%

Er is een verwarrend verborgen methode, die een nieuwe array construeert zonder de originele te muteren:

var oldArray = [[1],[2,3],[4]];
var newArray = Array.prototype.concat.apply([], oldArray);
console.log(newArray); // [ 1, 2, 3, 4 ]

Antwoord 4, autoriteit 10%

Het kan het beste worden gedaan met de Javascript-reduceerfunctie.

var arrays = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"], ["$0"], ["$15"],["$3"], ["$75"], ["$5"], ["$100"], ["$7"], ["$3"], ["$75"], ["$5"]];
arrays = arrays.reduce(function(a, b){
     return a.concat(b);
}, []);

Of, met ES2015:

arrays = arrays.reduce((a, b) => a.concat(b), []);

js-fiddle

Mozilla-documenten


Antwoord 5, autoriteit 7%

Er is een nieuwe native methode genaamd flatom dit precies te doen.

(Vanaf eind 2019 is flatnu gepubliceerd in de ECMA 2019-standaard, en [email protected](bibliotheek van babel) neemt het op in hun polyfill bibliotheek)

const arr1 = [1, 2, [3, 4]];
arr1.flat(); 
// [1, 2, 3, 4]
const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
// Flatten 2 levels deep
const arr3 = [2, 2, 5, [5, [5, [6]], 7]];
arr3.flat(2);
// [2, 2, 5, 5, 5, [6], 7];
// Flatten all levels
const arr4 = [2, 2, 5, [5, [5, [6]], 7]];
arr4.flat(Infinity);
// [2, 2, 5, 5, 5, 6, 7];

Antwoord 6, autoriteit 4%

De meeste antwoorden hier werken niet op enorme (bijvoorbeeld 200 000 elementen) arrays, en zelfs als ze dat wel doen, zijn ze traag. polkovnikov.ph’s antwoordlevert de beste prestaties, maar werkt niet voor diepe afvlakking.

Hier is de snelste oplossing, die ook werkt op arrays met meerdere nestingniveaus:

const flatten = function(arr, result = []) {
  for (let i = 0, length = arr.length; i < length; i++) {
    const value = arr[i];
    if (Array.isArray(value)) {
      flatten(value, result);
    } else {
      result.push(value);
    }
  }
  return result;
};

Voorbeelden

Enorme arrays

flatten(Array(200000).fill([1]));

Het verwerkt grote arrays prima. Op mijn computer duurt het ongeveer 14 ms om deze code uit te voeren.

Geneste arrays

flatten(Array(2).fill(Array(2).fill(Array(2).fill([1]))));

Het werkt met geneste arrays. Deze code produceert [1, 1, 1, 1, 1, 1, 1, 1].

Arrays met verschillende nestingniveaus

flatten([1, [1], [[1]]]);

Het heeft geen problemen met het afvlakken van arrays zoals deze.


Antwoord 7, autoriteit 3%

Update: het bleek dat deze oplossing niet werkt met grote arrays. Als je op zoek bent naar een betere, snellere oplossing, bekijk dan dit antwoord.


function flatten(arr) {
  return [].concat(...arr)
}

Is breidt eenvoudig arruit en geeft het als argumenten door aan concat(), die alle arrays in één samenvoegt. Het is gelijk aan [].concat.apply([], arr).

Je kunt dit ook proberen voor diepe afvlakking:

function deepFlatten(arr) {
  return flatten(           // return shalowly flattened array
    arr.map(x=>             // with each x in array
      Array.isArray(x)      // is x an array?
        ? deepFlatten(x)    // if yes, return deeply flattened x
        : x                 // if no, return just x
    )
  )
}

Bekijk demo op JSBin.

Referenties voor ECMAScript 6-elementen die in dit antwoord worden gebruikt:


Kanttekening: methoden zoals find()en pijlfuncties worden niet door alle browsers ondersteund, maar dit betekent niet dat u deze functies op dit moment niet kunt gebruiken. Gebruik gewoon Babel— het transformeert ES6-code in ES5.


Antwoord 8, autoriteit 2%

U kunt Underscoregebruiken:

var x = [[1], [2], [3, 4]];
_.flatten(x); // => [1, 2, 3, 4]

Antwoord 9, autoriteit 2%

Algemene procedures zorgen ervoor dat we de complexiteit niet elke keer hoeven te herschrijven als we een specifiek gedrag moeten gebruiken.

concatMap(of flatMap) is precies wat we nodig hebben in deze situatie.

// concat :: ([a],[a]) -> [a]
const concat = (xs,ys) =>
  xs.concat (ys)
// concatMap :: (a -> [b]) -> [a] -> [b]
const concatMap = f => xs =>
  xs.map(f).reduce(concat, [])
// id :: a -> a
const id = x =>
  x
// flatten :: [[a]] -> [a]
const flatten =
  concatMap (id)
// your sample data
const data =
  [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]]
console.log (flatten (data))

Antwoord 10

Als u een array met arrays met één element wilt afvlakken, hoeft u geen bibliotheek te importeren. Een eenvoudige lus is zowel de eenvoudigste als meest efficiënteoplossing:

for (var i = 0; i < a.length; i++) {
  a[i] = a[i][0];
}

Aan downvoters: lees de vraag, stem niet af omdat het niet past bij uw heel andere probleem. Deze oplossing is zowel de snelste als de eenvoudigste voor de gestelde vraag.


Antwoord 11

Een oplossing voor het meer algemene geval, wanneer u enkele niet-array-elementen in uw array kunt hebben.

function flattenArrayOfArrays(a, r){
    if(!r){ r = []}
    for(var i=0; i<a.length; i++){
        if(a[i].constructor == Array){
            r.concat(flattenArrayOfArrays(a[i], r));
        }else{
            r.push(a[i]);
        }
    }
    return r;
}

Antwoord 12

Hoe zit het met het gebruik van de methode reduce(callback[, initialValue])van JavaScript 1.8

list.reduce((p,n) => p.concat(n),[]);

Zou het werk doen.


Antwoord 13

Nog een ECMAScript 6-oplossing in functionele stijl:

Een functie declareren:

const flatten = arr => arr.reduce(
  (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []
);

en gebruik het:

flatten( [1, [2,3], [4,[5,[6]]]] ) // -> [1,2,3,4,5,6]

const flatten = arr => arr.reduce(
         (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []
       );
console.log( flatten([1, [2,3], [4,[5],[6,[7,8,9],10],11],[12],13]) )

Antwoord 14

const common = arr.reduce((a, b) => [...a, ...b], [])

Antwoord 15

Je kunt ook de nieuwe Array.flat()methode. Het werkt op de volgende manier:

let arr = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]].flat()
console.log(arr);

Antwoord 16

Je kunt Array.flat()met Infinityvoor elke diepte van geneste array.

var arr = [ [1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]], [[1,2,3,4], [1,2,[1,2,3]], [1,2,3,4,5,[1,2,3,4,[1,2,3,4]]]] ];
let flatten = arr.flat(Infinity)
console.log(flatten)

Antwoord 17

Let op:Wanneer Function.prototype.apply([].concat.apply([], arrays)) of de spread operator ([].concat(...arrays)) wordt gebruikt om een array af te vlakken, beide kunnen stackoverflows veroorzaken voor grote arrays, omdat elk argument van een functie op de stapel wordt opgeslagen.

Hier is een stapelveilige implementatie in functionele stijl die de belangrijkste eisen tegen elkaar afweegt:

  • herbruikbaarheid
  • leesbaarheid
  • beknoptheid
  • prestaties
// small, reusable auxiliary functions:
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc); // aka reduce
const uncurry = f => (a, b) => f(a) (b);
const concat = xs => y => xs.concat(y);
// the actual function to flatten an array - a self-explanatory one-line:
const flatten = xs => foldl(concat) ([]) (xs);
// arbitrary array sizes (until the heap blows up :D)
const xs = [[1,2,3],[4,5,6],[7,8,9]];
console.log(flatten(xs));
// Deriving a recursive solution for deeply nested arrays is trivially now
// yet more small, reusable auxiliary functions:
const map = f => xs => xs.map(apply(f));
const apply = f => a => f(a);
const isArray = Array.isArray;
// the derived recursive function:
const flattenr = xs => flatten(map(x => isArray(x) ? flattenr(x) : x) (xs));
const ys = [1,[2,[3,[4,[5],6,],7],8],9];
console.log(flattenr(ys));

Antwoord 18

ES6 Eén lijn afvlakken

Zie lodash flatten, underscore flatten (ondiepe true)

function flatten(arr) {
  return arr.reduce((acc, e) => acc.concat(e), []);
}

of

function flatten(arr) {
  return [].concat.apply([], arr);
}

Getest met

test('already flatted', () => {
  expect(flatten([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});
test('flats first level', () => {
  expect(flatten([1, [2, [3, [4]], 5]])).toEqual([1, 2, [3, [4]], 5]);
});

ES6 Eén lijn diep afvlakken

Zie lodash flattenDeep, underscore flatten

function flattenDeep(arr) {
  return arr.reduce((acc, e) => Array.isArray(e) ? acc.concat(flattenDeep(e)) : acc.concat(e), []);
}

Getest met

test('already flatted', () => {
  expect(flattenDeep([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]);
});
test('flats', () => {
  expect(flattenDeep([1, [2, [3, [4]], 5]])).toEqual([1, 2, 3, 4, 5]);
});

Antwoord 19

De spread-operator gebruiken:

const input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"], ["$22"], ["$10"]];
const output = [].concat(...input);
console.log(output); // --> ["$6", "$12", "$25", "$25", "$18", "$22", "$10"]

Antwoord 20

Als je alleen arrays hebt met 1 string-element:

[["$6"], ["$12"], ["$25"], ["$25"]].join(',').split(',');

zal het werk doen. Bt die specifiek overeenkomt met uw codevoorbeeld.


Antwoord 21

Een Haskelleske benadering

function flatArray([x,...xs]){
  return x ? [...Array.isArray(x) ? flatArray(x) : [x], ...flatArray(xs)] : [];
}
var na = [[1,2],[3,[4,5]],[6,7,[[[8],9]]],10];
    fa = flatArray(na);
console.log(fa);

Antwoord 22

ES6 manier:

const flatten = arr => arr.reduce((acc, next) => acc.concat(Array.isArray(next) ? flatten(next) : next), [])
const a = [1, [2, [3, [4, [5]]]]]
console.log(flatten(a))

Antwoord 23

var arrays = [["a"], ["b", "c"]];
Array.prototype.concat.apply([], arrays);
// gives ["a", "b", "c"]

(Ik schrijf dit alleen als een apart antwoord, gebaseerd op de opmerking van @danhbear.)


Antwoord 24

Ik raad een ruimtebesparende generatorfunctie:

function* flatten(arr) {
  if (!Array.isArray(arr)) yield arr;
  else for (let el of arr) yield* flatten(el);
}
// Example:
console.log(...flatten([1,[2,[3,[4]]]])); // 1 2 3 4

Antwoord 25

Ik zou liever de hele array transformeren, zoals het is, naar een string, maar in tegenstelling tot andere antwoorden, zou ik dat doen met JSON.stringifyen niet de toString()methode, die een ongewenst resultaat opleveren.

Met die JSON.stringify-uitvoer, hoef je alleen nog maar alle haakjes te verwijderen, het resultaat in te pakken met start & sluit haakjes nogmaals af en serveer het resultaat met JSON.parsedie de string weer tot “leven” brengt.

  • Kan oneindige geneste arrays aan zonder snelheidskosten.
  • Kan terecht Array-items verwerken die tekenreeksen zijn die komma’s bevatten.

var arr = ["abc",[[[6]]],["3,4"],"2"];
var s = "[" + JSON.stringify(arr).replace(/\[|]/g,'') +"]";
var flattened = JSON.parse(s);
console.log(flattened)

Antwoord 26

Dat is niet moeilijk, herhaal gewoon de arrays en voeg ze samen:

var result = [], input = [["$6"], ["$12"], ["$25"], ["$25"], ["$18"]];
for (var i = 0; i < input.length; ++i) {
    result = result.concat(input[i]);
}

Antwoord 27

Het lijkt erop dat dit een baan voor RECURSION lijkt!

  • Verwerkt meerdere niveaus van nesten
  • Verwerkt lege arrays en niet-array parameters
  • Heeft geen mutatie
  • Niet afhankelijk van moderne browserfuncties

Code:

var flatten = function(toFlatten) {
  var isArray = Object.prototype.toString.call(toFlatten) === '[object Array]';
  if (isArray && toFlatten.length > 0) {
    var head = toFlatten[0];
    var tail = toFlatten.slice(1);
    return flatten(head).concat(flatten(tail));
  } else {
    return [].concat(toFlatten);
  }
};

Gebruik:

flatten([1,[2,3],4,[[5,6],7]]);
// Result: [1, 2, 3, 4, 5, 6, 7] 

Antwoord 28

Ik heb het gedaan met recursie en sluitingen

function flatten(arr) {
  var temp = [];
  function recursiveFlatten(arr) { 
    for(var i = 0; i < arr.length; i++) {
      if(Array.isArray(arr[i])) {
        recursiveFlatten(arr[i]);
      } else {
        temp.push(arr[i]);
      }
    }
  }
  recursiveFlatten(arr);
  return temp;
}

Antwoord 29

Ik was aan het dollen met ES6-generatorenonlangs en schreef deze kern. Die bevat…

function flatten(arrayOfArrays=[]){
  function* flatgen() {
    for( let item of arrayOfArrays ) {
      if ( Array.isArray( item )) {
        yield* flatten(item)
      } else {
        yield item
      }
    }
  }
  return [...flatgen()];
}
var flatArray = flatten([[1, [4]],[2],[3]]);
console.log(flatArray);

In feite ben ik een generator aan het maken die over de originele invoerarray loopt. Als hij een array vindt, gebruikt hij de yield*operator in combinatie met recursie om de interne arrays continu af te vlakken. Als het item geen array is, levert het gewoon ophet enkele artikel. Gebruik vervolgens de ES6 Spread-operator(ook bekend als splat operator) Ik maak de generator plat tot een nieuwe array-instantie.

Ik heb de prestaties hiervan niet getest, maar ik denk dat het een mooi eenvoudig voorbeeld is van het gebruik van generatoren en de yield*-operator.

Maar nogmaals, ik was gewoon gek, dus ik weet zeker dat er betere manieren zijn om dit te doen.


Antwoord 30

gewoon de beste oplossing zonder lodash

let flatten = arr => [].concat.apply([], arr.map(item => Array.isArray(item) ? flatten(item) : item))

Other episodes