2015-05-05 3 views
7

Я упражняюсь и пытаюсь написать рекурсивную функцию сглаживания массива. Код идет здесь:Сжатие рекурсивного массива 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; 
} 

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

+0

Подобно тому, как побочного сведению: http://stackoverflow.com/questions/10865025/merge-flatten-a-array-of-arrays-in-javascript – Nit

+0

'flatten.apply (это, аргументы [i]);' но это не единственная проблема. – basilikum

ответ

-1

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

в качестве примера если Len (аргументы [я]) == 0 возвращение

+0

Почему это не останавливается, когда i == arguments.length истинно? – yxfxmx

+0

@yxfxmx он делает. – Sacho

+0

Итак, в чем проблема? ( – yxfxmx

11

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

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

Вот еще один современный: функция flatten (array, accu = []) { array.forEach (a => { if (Array.isArray (a)) flatten (a, accu) еще accu.push (a) }) return accu } – dotnetCarpenter

2

В вашем коде отсутствует инструкция 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] 
0

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

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

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

(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] 
0

Это решение 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());

2

Haskellesque подход ...

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

0

Если кто-то ищет Свести массив объектов (например, 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'} 
] 

Результат flatten(test):[{title: '1'}, {title: '2'}, {title: '3'}, {title: '4'}, {title: '5'}]

DEMO:https://jsfiddle.net/0w14shc6/

Смежные вопросы