【问题标题】:How can get a count with nested objects with a certain property?如何获得具有特定属性的嵌套对象的计数?
【发布时间】:2015-06-29 02:12:54
【问题描述】:

好的,所以我正在使用 Angular 将 json 保存到我的计算机以重新创建 github 成绩簿。

我可以通过我的 $http 请求获取数据,但为了我的爱,我只想计算带有“Not Yet”标签的问题数量。

这里是javascript:

$http.get('/api/github/repos/issues/all_issues/00All.json')
  .then(function(response) {
    console.log(response.data[0]);
    var counter = 0;
    for(var index = 0; index < response.data.length; index++) {
      if(response.data[index].labels[0].name == "Not Yet") {
        counter++;
      };
    };
    console.log(counter);
  });

这是最新的尝试,我也尝试过使用lodash更早地获得它:

$http.get('/api/github/repos/issues/all_issues/00All.json')
  .then(function(response) {
    console.log(response);
    mile.notYet.width = _.forEach(response.data, function(n){
      var counter = 0;
      if(_.result(_.find(n.labels[0], 'name')) == "Not Yet") {
        counter++;
      }
      console.log(counter);
      counter = ((counter/10) * 100) + '%';
    });
  });

这是一些json数据:

[
  {
    "url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11",
    "labels_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/labels{/name}",
    "comments_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/comments",
    "events_url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11/events",
    "html_url": "https://github.com/TheIronYard--Orlando/2015--SUMMER--FEE/issues/11",
    "id": 73013825,
    "number": 11,
    "title": "00 -- Brace Yourself -- BEN GRIFFITH",
    "user": {
      "login": "Epicurean306",
      "id": 11682684,
      "avatar_url": "https://avatars.githubusercontent.com/u/11682684?v=3",
      "gravatar_id": "",
      "url": "https://api.github.com/users/Epicurean306",
      "html_url": "https://github.com/Epicurean306",
      "followers_url": "https://api.github.com/users/Epicurean306/followers",
      "following_url": "https://api.github.com/users/Epicurean306/following{/other_user}",
      "gists_url": "https://api.github.com/users/Epicurean306/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/Epicurean306/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/Epicurean306/subscriptions",
      "organizations_url": "https://api.github.com/users/Epicurean306/orgs",
      "repos_url": "https://api.github.com/users/Epicurean306/repos",
      "events_url": "https://api.github.com/users/Epicurean306/events{/privacy}",
      "received_events_url": "https://api.github.com/users/Epicurean306/received_events",
      "type": "User",
      "site_admin": false
    },
    "labels": [
      {
        "url": "https://api.github.com/repos/TheIronYard--Orlando/2015--SUMMER--FEE/labels/Not%20Yet",
        "name": "Not Yet",
        "color": "e11d21"
      }
    ],

如你所见,labels属性是一个对象,嵌套在数组中,嵌套在对象中,嵌套在数组中,真可爱。每次放置标签 [0] 都会导致我出错,并且不会让我计数。谁能告诉我我在哪里搞砸了?谢谢!

【问题讨论】:

    标签: javascript json angularjs lodash


    【解决方案1】:

    如果您需要一个包含 lodash 的解决方案,它比原生高阶函数的性能要高得多,那么您可以尝试以下解决方案:

    var size = _(response.data)
       .pluck('labels')
       .flatten()
       .where({ name: 'Not Yet' })
       .size();
    

    更新:

    如果您希望它更具可重用性,您可以为克隆的链式序列保存一个引用,并为该克隆的序列提供另一个数组。

    var data1 = [/*array from data1*/];
    var data2 = [/*array from data2*/];
    
    var notYetSequence = _(data1)
      .pluck('labels')
      .flatten()
      .where({ name: 'Not Yet' });
    
    notYetSequence.size(); // returns data 1 count
    notYetSequence.plant(data2).size(); // returns data 2 count
    

    【讨论】:

    • 当然:)。上面的代码懒惰地评估代码。实际上只是执行一个循环。一个参考是this
    • 因此,如果它是 1 条循环语句与 3 条语句,则它只是“性能提高一点点”而不是“更多”
    • 无论如何,您将如何量化“只是性能提高一点点”和“更多”?这些只是文字游戏..
    • 它是 :-) 没有过滤并且在这里进行惰性评估无济于事,因为您仍然需要获取总集合的大小。因此,lodash 可能带来的唯一好处是为临时数组分配内存,对于每秒少于几十万次的操作和少于几千个元素的数组来说,内存分配可以忽略不计。我同意 lodash 可以提高性能,但在非常具体的用例中。绝对不是一般的。
    • 你可能是对的,也许这是有争议的。就好处而言,您可以说 lodash 贡献了很多因素:浏览器兼容性、简洁性、可读性以及这种“一点点性能提升”。
    【解决方案2】:

    这个任务你不需要 lodash

    var cnt = response.data
        .map(function(i) { return i.labels; })
             // here we extract labels object only (and get an array of arrays of objects)
        .map(function(i) { return i.filter(function(l) { return l.name == 'Not yet'; }).length; })
             // then for every nested array we return a number of items with 
             // Not Yet names (and get an array of numbers)
        .filter(function(c) { return c > 0; })
             // then we filter issues that don't have one (and still get an array of numbers)
        .length;
             // and finally get length (which is a number)
    

    【讨论】:

    • 如果我在你的作业中找到此代码,@gatorpazz,我最好找到解释。 ;)
    • 另外,最好使用 Lodash 来实现跨浏览器兼容性:并非所有浏览器实现都在 Array 上提供迭代方法。例如,filter 仅在 IE9+ 中:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • @ALtheX——mapfilter 功能很容易被 for 循环替换(执行速度也更快)。
    • 我认为关于性能的最大问题是构建了这么多临时数组(两个 maps 和两个 filters)和所有函数调用:除了 mapfilter 还有 4 个回调。将其与普通的 for 循环进行比较,其中唯一的函数调用是使用正则表达式或 indexOf 为每个 label 对象测试一次“尚未”。
    • @RobG 我的注意力转移到了流处理和响应式+函数式编程上,我不能再编写命令式循环了;'-( PS: +1'd you
    【解决方案3】:

    作为比较,一个普通的 for 循环看起来像:

      var data = response.data;
      var count = 0;
      var re = /not yet/i;
    
      for (var a, i=0, iLen=data.length; i<iLen; i++) {
        a = data[i].labels;
        for (var j=0, jLen=a.length; j<jLen; j++) {
          if (re.test(a[j].name)) ++count;
        }
      }
    

    所以无论哪种方式实际上都没有很多代码,for循环将与所有浏览器兼容(尽管使用 xmlHTTPRequest 意味着至少 ed 3+)并且最快......当然未经测试。 ;-)

    【讨论】:

      猜你喜欢
      • 2017-07-07
      • 2018-11-30
      • 1970-01-01
      • 2016-08-17
      • 1970-01-01
      • 1970-01-01
      • 2020-07-20
      • 2020-10-25
      • 2018-07-20
      相关资源
      最近更新 更多