Реверсивное выравнивание массивов Javascript

Я тренируюсь и пытаюсь написать рекурсивную функцию сглаживания массива. Код идет здесь:

function flatten() {
    var flat = [];
    for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] instanceof Array) {
            flat.push(flatten(arguments[i]));
        }
        flat.push(arguments[i]);
    }
    return flat;
}

Проблема в том, что если я передаю туда массив или вложенные массивы, я получаю ошибку "максимальный размер стека вызовов". Что я делаю неправильно?

Ответ 1

Проблема в том, как вы передаете обработку массива, если это значение является массивом, тогда вы продолжаете называть его, вызывая бесконечный цикл

function flatten() {
    var flat = [];
    for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] instanceof Array) {
            flat.push.apply(flat, flatten.apply(this, arguments[i]));
        } else {
            flat.push(arguments[i]);
        }
    }
    return flat;
}

Демо: Fiddle

Здесь более современная версия:

function flatten(items) {
  const flat = [];

  items.forEach(item => {
    if (Array.isArray(item)) {
      flat.push(...flatten(item));
    } else {
      flat.push(item);
    }
  });

  return flat;
}

Ответ 2

Аскопельский подход...

function flatArray([x,...xs]){
  return x !== undefined ? [...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);

Ответ 3

В вашем коде отсутствует инструкция else, а рекурсивный вызов неверен (вы передаете один и тот же массив снова и снова, а не передаете его элементы).

Ваша функция может быть написана следующим образом:

function flatten() {
    // variable number of arguments, each argument could be:
    // - array
    //   array items are passed to flatten function as arguments and result is appended to flat array
    // - anything else
    //   pushed to the flat array as-is
    var flat = [],
        i;
    for (i = 0; i < arguments.length; i++) {
        if (arguments[i] instanceof Array) {
            flat = flat.concat(flatten.apply(null, arguments[i]));
        } else {
            flat.push(arguments[i]);
        }
    }
    return flat;
}

// flatten([[[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]], [[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]]]);
//            [0, 1, 2,   0, 1, 2,     0, 1, 2,   0, 1, 2,       0, 1, 2,   0, 1, 2,     0, 1, 2,   0, 1, 2]

Ответ 4

Если кто-то ищет сгладить массив объектов (например, tree), то вот код:

function flatten(items) {
  const flat = [];

  items.forEach(item => {
    flat.push(item)
    if (Array.isArray(item.children) && item.children.length > 0) {
      flat.push(...flatten(item.children));
      delete item.children
    }
    delete item.children
  });

  return flat;
}

var test = [
	{children: [
      {children: [], title: '2'}
      ],
  title: '1'},
	{children: [
      {children: [], title: '4'},
      {children: [], title: '5'}
      ],
  title: '3'}
]

console.log(flatten(test))

Ответ 5

Если вы предполагаете, что ваш первый аргумент является массивом, вы можете сделать это довольно простым.

function flatten(a) {
    return a.reduce((flat, i) => {
      if (Array.isArray(i)) {
        return flat.concat(flatten(i));
      }
      return flat.concat(i);
    }, []);
  }

Если вы хотите сгладить несколько массивов, просто сравните их перед прохождением.

Ответ 6

Если элемент является массивом, мы просто добавляем все остальные элементы в этот массив

function flatten(array, result) {
  if (array.length === 0) {
    return result
  }
  var head = array[0]
  var rest = array.slice(1)
  if (Array.isArray(head)) {
    return flatten(head.concat(rest), result)
  }
  result.push(head)
  return flatten(rest, result)
}

console.log(flatten([], []))
console.log(flatten([1], []))
console.log(flatten([1,2,3], []))
console.log(flatten([1,2,[3,4]], []))
console.log(flatten([1,2,[3,[4,5,6]]], []))
console.log(flatten([[1,2,3],[4,5,6]], []))
console.log(flatten([[1,2,3],[[4,5],6,7]], []))
console.log(flatten([[1,2,3],[[4,5],6,[7,8,9]]], []))

Ответ 7

[...arr.toString().split(",")]

Используйте метод toString() в Object. Используйте оператор распространения (...), чтобы создать массив строк и разделить его на ",".

Пример:

let arr =[["1","2"],[[[3]]]]; // output : ["1", "2", "3"]

Ответ 8

Это решение Vanilla JavaScript для этой проблемы

var _items = {'keyOne': 'valueOne', 'keyTwo': 'valueTwo', 'keyThree': ['valueTree', {'keyFour': ['valueFour', 'valueFive']}]};

// another example
// _items = ['valueOne', 'valueTwo', {'keyThree': ['valueTree', {'keyFour': ['valueFour', 'valueFive']}]}];

// another example
/*_items = {"data": [{
    "rating": "0",
    "title": "The Killing Kind",
    "author": "John Connolly",
    "type": "Book",
    "asin": "0340771224",
    "tags": "",
    "review": "i still haven't had time to read this one..."
}, {
    "rating": "0",
    "title": "The Third Secret",
    "author": "Steve Berry",
    "type": "Book",
    "asin": "0340899263",
    "tags": "",
    "review": "need to find time to read this book"
}]};*/

function flatten() {
    var results = [],
        arrayFlatten;

    arrayFlatten = function arrayFlattenClosure(items) {
        var key;
        
        for (key in items) {
            if ('object' === typeof items[key]) {
                arrayFlatten(items[key]);
            } else {
                results.push(items[key]);
            }
        }
    };

    arrayFlatten(_items);
    
    return results;
}

console.log(flatten());

Ответ 9

Это должно работать

function flatten() {
    var flat = [
    ];
    for (var i = 0; i < arguments.length; i++) {
        flat = flat.concat(arguments[i]);
    }
    var removeIndex = [
    ];
    for (var i = flat.length - 1; i >= 0; i--) {
        if (flat[i] instanceof Array) {
            flat = flat.concat(flatten(flat[i]));
            removeIndex.push(i);
        }
    }
    for (var i = 0; i < removeIndex.length; i++) {
        flat.splice(removeIndex - i, 1);
    }
    return flat;
}

Ответ 10

Другие ответы уже указывали на источник неисправности OP-кода. Написав более описательный код, проблема буквально сводится к "обнаружению массива /-reduce/-concat-recursion"...

(function (Array, Object) {


//"use strict";


  var
    array_prototype       = Array.prototype,

    array_prototype_slice = array_prototype.slice,
    expose_internal_class = Object.prototype.toString,


    isArguments = function (type) {
      return !!type && (/^\[object\s+Arguments\]$/).test(expose_internal_class.call(type));
    },
    isArray     = function (type) {
      return !!type && (/^\[object\s+Array\]$/).test(expose_internal_class.call(type));
    },

    array_from  = ((typeof Array.from == "function") && Array.from) || function (listAlike) {
      return array_prototype_slice.call(listAlike);
    },


    array_flatten = function flatten (list) {
      list = (isArguments(list) && array_from(list)) || list;

      if (isArray(list)) {
        list = list.reduce(function (collector, elm) {

          return collector.concat(flatten(elm));

        }, []);
      }
      return list;
    }
  ;


  array_prototype.flatten = function () {
    return array_flatten(this);
  };


}(Array, Object));

заимствование кода из одного из других ответов в качестве доказательства концепции...

console.log([
  [[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]],
  [[[0, 1, 2], [0, 1, 2]], [[0, 1, 2], [0, 1, 2]]]
].flatten());
//[0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, ..., ..., ..., 0, 1, 2]

Ответ 11

Здесь рекурсивная реализация сокращения, взятая из абсурда, который имитирует lodash _.concat()

Может принимать любое количество аргументов массива или не массива. Массивы могут быть любого уровня глубины. В результате вы получите один массив сглаженных значений.

export const concat = (...arrays) => {
  return flatten(arrays, []);
}

function flatten(array, initial = []) {
  return array.reduce((acc, curr) => {
    if(Array.isArray(curr)) {
      acc = flatten(curr, acc);
    } else {
      acc.push(curr);
    }
    return acc;
  }, initial);
}

В качестве входных данных может использоваться любое количество массивов или не массивов.

Источник: я автор абсурда

Ответ 12

Современный, но не кроссбраузерный

function flatten(arr) {
  return arr.flatMap(el => {
    if(Array.isArray(el)) {
        return flatten(el)
    } else {
      return el;
    }
})

}

Ответ 13

The clean way to flatten an Array in 2019 с помощью ES6 можно использовать flat():

const array = [1, 1, [2, 2], [[3, [4], 3], 2]]

// All layers
array.flat(Infinity) // [1, 1, 2, 2, 3, 4, 3, 2]

// Varying depths
array.flat() // [1, 1, 2, 2, Array(3), 2]

array.flat(2) // [1, 1, 2, 2, 3, Array(1), 3, 2]
array.flat().flat() // [1, 1, 2, 2, 3, Array(1), 3, 2]

array.flat(3) // [1, 1, 2, 2, 3, 4, 3, 2]
array.flat().flat().flat() // [1, 1, 2, 2, 3, 4, 3, 2]

Документы Mozilla

Могу ли я использовать - 80% сент. 2019 г.

Ответ 14

вы должны добавить условие остановки для рекурсии.

в качестве примера if len (arguments [i]) == 0 return