2013-05-26 4 views
-1

Скажем, у меня есть один большой массив какКак создать коллекцию массивов из одного массива?

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] 

и хотел бы разделить его в массив кортежей как

[[1,2], [3,4], [5,6], [7,8], [9,10], [11,12], [13,14] /*, ... */ ] // (for n=2) 

Есть некоторые простой способ для достижения этой цели? Для меня было бы достаточно специального случая n = 2.

+3

Что вы пробовали? Где у вас проблемы? Что вы не понимаете, чтобы добиться этого? –

+1

просто напишите код 'javascript' для этого, выполните некоторую итерацию. – sabithpocker

+1

По сути, я не понимаю, как написать это - вот почему я задаю вопрос? – Andy

ответ

5

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

for (var i=0; i<arr.length; i+=2) { 
    result.push([arr[i], arr[i+1]]); 
} 

Придумал с этим, он должен работать для любого числа «карманов» или что вы хотите назвать их. Он проверяет undefined поэтому он работает с нечетным числом элементов:

Array.prototype.pockets = function(n) { 

    var result = [], 
     pocket = [], 
     i, j; 

    for (i=0; i<this.length; i+=n) { 
    pocket.length = 0; 
    for (j=1; j<n; j++) if (this[i+j] != null) pocket.push(this[i+j]); 
    result.push([this[i]].concat(pocket)); 
    } 

    if (arguments.length > 1) { 
    return result.pockets.apply(result, [].slice.call(arguments,1)); 
    } 

    return result; 
}; 

// Usage: 
var arr = [1,2,3,4,5,6,7,8,9,10,11]; 

arr.pockets(2); //=> [[1,2],[3,4],[5,6],[7,8],[9,10],[11]] 
arr.pockets(3); //=> [[1,2,3],[4,5,6],[7,8,9],[10,11]] 

// Recursive: 
arr.pockets(1,3); //=> [ [[1],[2],[3]], [[4],[5],[6]], [[7],[8],[9]], [[10],[11]] ] 
+0

У вас есть логическая ошибка. Наверное, не нужно '++ i', если вы делаете' i + = 2' в цикле. –

+0

Да, 'i ++' в цикле должен работать с '++ i' внутри. – elclanrs

+0

@ elclanrs: Это не то, как я это сделал (слишком запутанный для человека, который его поддерживает позже, ненужная операция магазина), но да, он должен работать. –

3

Для варианта подчеркивания, вы можете добиться этого с _.groupBy(), группировка по индексу пункта:

var doubles = _.groupBy(singles, function (num, i) { 
    return Math.floor(i/2); 
}); 

Хотя, так как _.groupBy() возвращает Object, получая Array берет дополнительную работу:

_.mixin({ 
    segment: function (coll, per) { 
     var result = []; 
     _.chain(coll) 
      .groupBy(function (item, i) { return Math.floor(i/per)}) 
      .each(function (group, key) { result[key] = group; }) 
     return result; 
    } 
}); 

var singles = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]; 

var doubles = _.segment(singles, 2); 
var triples = _.segment(singles, 3); 
+0

фантастическое спасибо! – Andy

+4

Хорошее решение и легко расширяемое до n-групп. Слово предупреждения: оно опирается на порядок итерации объекта, который документируется как произвольный, но на самом деле последовательный - это все известные браузеры. – georg

5

Это может быть d один намного проще с помощью Array.slice:

function grouper(lst, size) { 
    var result = [], i=0, n=lst.length; 
    while(i < n) { 
     result.push(lst.slice(i, i+size)); 
     i += size; 
    } 
    return result 
} 

Это также намного эффективнее: http://jsperf.com/grouper

+0

Мне это больше нравится. Я бы использовал 'for' вместо' while'. – georg

+0

Это лучше, чем мое решение. Хороший JSPerf. – elclanrs

+0

Вот суть, которую я сохраняю на основе этого ответа, если кто-то этого хочет: https://gist.github.com/elclanrs/5652418 – elclanrs

1

В питоне это может быть сделано с zip(*[iter(xs)]*n). Просто для удовольствия, вот реализация JS:

Начнет с генератором бедного человека (это все, что мы не получили до ES6 спредов вокруг):

StopIteration = {"name": "StopIteration"} 

function iter(xs) { 
    if('next' in xs) 
     return xs; 
    var i = 0; 
    return { 
     next: function() { 
      if(i >= xs.length) 
       throw StopIteration; 
      return xs[i++]; 
     } 
    } 
} 

next = function(it) { return it.next() } 

zip() тривиальна:

zip = function() { 
    var args = [].map.call(arguments, iter), chunks = []; 
    while(1) { 
     try { 
      chunks.push(args.map(next)); 
     } catch(StopIteration) { 
      return chunks; 
     } 
    } 
} 

Теперь, чтобы создать сцепленные пары просто пройти один и тот же ITER дважды zip:

xs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] 

it = iter(xs) 
a = zip(it, it) 

console.log(a) 
// [[1,2],[3,4],[5,6],[7,8],[9,10],[11,12]] 

для N -пар требуется дополнительная утилита:

repeat = function(x, n) { 
    for(var a = []; n; n--) 
     a.push(x); 
    return a; 
} 

a = zip.apply(this, repeat(iter(xs), 5)) 

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

Обратите внимание, что нравится в Python это полоски неполные куски.

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