2014-01-10 2 views
4

У меня есть сложный массив объектов с вложенными массивами. Следующие работы для извлечения определенных объектов, но это одна из самых уродливых вещей, которые я написал.Javascript: Улучшите четыре вложенных цикла?

Есть ли у вас темная магия javascript, чтобы сделать это элегантно?

function getEighthInsertionBlocks() { 
    var struct = Lifestyle.Pagination.structure; 
    var blocks = []; 
    for (var i = 0; i<struct.length; i++) { 
     var page = struct[i]; 
     var layers = page.children; 
     for (var j=0; j<layers.length; j++) { 
      var layer = layers[j]; 
      if (layer.className === 'EighthPageLayer') { 
       var rows = layer.children; 
       for (var k=0; k<rows.length; k++) { 
        var row = rows[k]; 
        eBlocks = row.children; 
        for (var l=0; l<eBlocks.length; l++) { 
         blocks.push(eBlocks[l]); 
        } 
       } 
      } 
     } 
    } 

    return blocks; 
} 

Не то, чтобы я был большим поклонником кодового гольфа, но ... это ужасно.

+1

Вы точно на одном уровне. – tenub

+0

Просто подумайте, возможно ли более эффективно использовать цикл foreach вместо – RyanS

+1

Извлечь каждый цикл в метод? –

ответ

0

Обычно я предпочитаю использовать forEach для удобства чтения, но это субъективно.

function isEighthPageLayer(layer){ 
    return layer.className === "EighthPageLayer" 
} 

function getEighthInsertionBlocks(struct) { 
    var blocks = []; 
    struct.forEach(function(page){ 
     page.layers 
      .filter(isEighthPageLayer) 
      .forEach(function(layer) { 
       layer.children.forEach(function(row){ 
        row.children.forEach(function(eBlocks){ 
         blocks.push(eBlocks); 
        }); 
       }); 
      }); 
     }); 
    }); 
    return blocks; 
} 
+0

Конечно, цель состоит в том, чтобы извлечь некоторые функции из фильтра, для каждого. Я думаю, что лучшим кандидатом являются функции, принимающие аргумент слоя. Я предупреждаю. – farvilain

+0

@Carth да, время, чтобы изучить английский для меня: -/ – farvilain

+0

@farvilian вы могли бы извлечь функции, переданные 'forEach' в переменные, и это было бы очень изящное решение – Stephen

3

Вы можете написать общий итератор, который позволит сократить код в последовательные блоки:

var iterator = function(collection, callback){ 
    var length = collection.length; 
    var results = []; 
    var result; 
    for (var i = 0; i < collection.length; i++){ 
     result = callback(colleciton[i], i); 
     if (result){ 
      results = results.concat(result); 
     } 
    } 
    return results; 
}; 

function getEighthInsertionBlocks() { 
    var struct = Lifestyle.Pagination.structure; 
    var layers = iterator(struct, function(page){ return page.children; }); 
    var rows = iterator(layers, function(layer){ 
     return layer.className === 'EighthPageLayer' ? layer.children : null; 
    }); 
    return iterator(rows, function(eBlocks, index){ return eblocks[index]; }); 
} 
+1

так приятно! :) Лучше, чем моя ! – farvilain

+0

Для этого нам нужно объединить результаты, а не нажимать их. В противном случае мы эффективно реализуем 'Array.prototype.map'. – Peter

+0

@Peter Я не уверен, что следую вашей логике. Это работает без concat. Кроме того, 'Array.prototype.map' не поддерживает IE8 (в случае необходимости). – Stephen

0

Это интересная задача. Чтобы избежать глубокого вложения, вам нужен общий итератор, который можно использовать рекурсивно, но на вашей итерации есть несколько особых случаев. Итак, я попытался создать общий итератор, с помощью которого можно передать объект опций, чтобы указать особые условия. Вот что я придумал. Поскольку у меня нет набора выборки данных, это не проверялось, но, надеюсь, вы видите идею:

function iterateLevel(data, options, level, output) { 
    console.log("level:" + level); 
    console.log(data); 
    var fn = options[level] && options[level].fn; 
    for (var i = 0; i < data.length; i++) { 
     if (!fn || (fn(data[i]) === true)) { 
      if (level === options.endLevel) { 
       output.push(data[i]); 
      } else { 
       iterateLevel(data[i].children, options, level + 1, output); 
      } 
     } 
    } 
} 

var iterateOptions = { 
    "1": { 
     fn: function(arg) {return arg.className === 'EighthPageLayer'} 
    }, 
    "endLevel": 3 
} 
var blocks = []; 
iterateLevel(Lifestyle.Pagination.structure, iterateOptions, 0, blocks); 

Идея заключается в том, что параметры объекта могут иметь дополнительную функцию фильтра для каждого уровня, и он говорит вам, как многие уровни снижаются.

Работа демо: http://jsfiddle.net/jfriend00/aQs6h/

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