如何使用 Lodash 从嵌套对象集合中获取图像数组?

How can i get an array of images from a collection of nested objects with Lodash?

 {
     "shop": {
         "homebackground": "http://padmenu.s3.amazonaws.com/15/11/2014/05/08/2ec2ff61-d6a0-11e3-8857-10ddb1e6e201.jpg",
         "name": {
             "tr": "My Shop"
         },
         "menus": [{
                 "name": {
                     "en": "Menu"
                 },
                 "children": [{
                     "name": {
                         "en_US": "Category"
                     },
                     "images": [
                         "http://www.progressivedental-ellenlimdds.com/wp-content/uploads/2014/06/red-wine.jpg"
                     ],
                     "children": [{
                         "name": {
                             "en_US": "Item"
                         },
                         "images": [
                             "http://res.cloudinary.com/finedine/image/upload/c_fill,g_center,h_600/v1435916818/WIne-Bottle_uz03a0.jpg",
                             "http://media.riepenau.com/wines/17973_b.jpg",
                             "http://lorempixel.com/400/400/food/3",
                             "http://lorempixel.com/400/400/food/4",
                             "http://lorempixel.com/400/400/food/5",
                             "http://lorempixel.com/400/400/food/6",
                             "http://lorempixel.com/400/400/food/7"
                         ]
                     }]
                 }]
             }]
         }
     }

我想 select 商店 "children" 对象中的所有 "images" 数组。 我如何使用 Lodash 库来做到这一点? 输出应该是一个由图像 url 组成的数组: ["url1","url2","url3"]

伪代码

你可以用一点递归来解决这个问题:

  1. 获取子列表。
  2. pluck 的子列表中提取所有图像。
  3. 对所有后代重复步骤 1。
  4. 合并所有结果并展平。

核心代码

function deepExtract(collection, childKey, property) {
  var exists = _.negate(_.isEmpty);
  var children = _.chain(collection).pluck(childKey).filter(exists).flatten();

  if (_.isEmpty(children.value())) {
    return [];
  }

  var images = children.pluck(property).value();
  var descendantImages = deepExtract(children.value(), childKey, property);

  return _.flatten(images.concat(descendantImages));
};

var tree = _.chain(data).get('shop.menus').value();

var images = deepExtract(tree, 'children', 'images');

演示

var data = {
  "shop": {
    "homebackground": "http://padmenu.s3.amazonaws.com/15/11/2014/05/08/2ec2ff61-d6a0-11e3-8857-10ddb1e6e201.jpg",
    "name": {
      "tr": "My Shop"
    },
    "menus": [{
      "name": {
        "en": "Menu"
      },
      "children": [{
        "name": {
          "en_US": "Category"
        },
        "images": [
          "http://www.progressivedental-ellenlimdds.com/wp-content/uploads/2014/06/red-wine.jpg"
        ],
        "children": [{
          "name": {
            "en_US": "Item"
          },
          "images": [
            "http://res.cloudinary.com/finedine/image/upload/c_fill,g_center,h_600/v1435916818/WIne-Bottle_uz03a0.jpg",
            "http://media.riepenau.com/wines/17973_b.jpg",
            "http://lorempixel.com/400/400/food/3",
            "http://lorempixel.com/400/400/food/4",
            "http://lorempixel.com/400/400/food/5",
            "http://lorempixel.com/400/400/food/6",
            "http://lorempixel.com/400/400/food/7"
          ]
        }]
      }]
    }]
  }
};

function deepExtract(collection, childKey, property) {
  var exists = _.negate(_.isEmpty);
  var children = _.chain(collection).pluck(childKey).filter(exists).flatten();

  if (_.isEmpty(children.value())) {
    return [];
  }

  var images = children.pluck(property).value();
  var descendantImages = deepExtract(children.value(), childKey, property);

  return _.flatten(images.concat(descendantImages));
};

var tree = _.chain(data).get('shop.menus').value();
log(deepExtract(tree, 'children', 'images'));


// Helper method to output to screen
function log(value) {
    document.getElementById("output").innerHTML += JSON.stringify(value, null, 2) + "\n"
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>
<pre id="output"></pre>

解决此问题的最简单方法是递归地提取 children 及其后代。重点在getImages()函数中;其中它将所有 children 数组展平在一个级别,提取每个图像数组并压缩所有项目以删除未定义的值(由 children 引起的没有图像),然后展平图像数组并准备连接。递归的停止点是当前 children 没有图像时,返回一个空数组。如果找到图像,那么我们递归地连接所有可能的后代图像。至于我们如何获得后代,我们使用与获得 images 数组相同的链接序列,但使用 children 作为采摘键。

DEMO

function getImages(children) {
  var images = _(children).flatten().pluck('images').compact().flatten().value();
  if(_.isEmpty(images)) {
    return [];
  }
  var descendants = _(children).flatten().pluck('children').compact().flatten().value();
  return images.concat(getImages(descendants));
}

function getShopImages(data) {
  var children = _.pluck(data.shop.menus, 'children');
  return getImages(children);
}

console.log(getShopImages(data));

我在这里找到了我的问题的替代解决方案:

  var children = _(shop.menus[0].children)
    .thru(function(coll) {
        return _.union(coll, _.pluck(coll, 'children'));
    })
    .flatten();

var images = _.chain(children).pluck('images').flattenDeep().compact().uniq().value();

输出"images"是一个图像数组。