【问题标题】:Selecting distinct values from a JSON从 JSON 中选择不同的值
【发布时间】:2013-07-22 05:28:51
【问题描述】:

我的 JSON 如下

{"DATA": [{"id":11,"name":"ajax","subject":"OR","mark":63},
{"id":12,"name":"javascript","subject":"OR","mark":63},
{"id":13,"name":"jquery","subject":"OR","mark":63},
{"id":14,"name":"ajax","subject":"OR","mark":63},
{"id":15,"name":"jquery","subject":"OR","mark":63},
{"id":16,"name":"ajax","subject":"OR","mark":63},
{"id":20,"name":"ajax","subject":"OR","mark":63}],"COUNT":"120"}

有什么好的方法可以从这个JSON中找出distinct name

结果javascript,jquery,ajax

我可以使用以下方法来做到这一点

var arr=[''];
var j=0;
for (var i = 0; i < varjson.DATA.length; i++) {
  if($.inArray(varjson.DATA[i]["name"],arr)<0){
      arr[j]=varjson.DATA[i]["name"];
      j++;
  }
}

有没有better method 给了我更好的性能?

【问题讨论】:

  • 这是不可能的。我想在某处显示所有这些并想选择不同的

标签: javascript jquery json


【解决方案1】:

如果你想节省一些循环,我会使用一个对象和一个数组:

var lookup = {};
var items = json.DATA;
var result = [];

for (var item, i = 0; item = items[i++];) {
  var name = item.name;

  if (!(name in lookup)) {
    lookup[name] = 1;
    result.push(name);
  }
}

通过这种方式,您基本上避免了indexOf / inArray 调用,并且您将获得一个可以比迭代对象的属性更快地迭代的数组——也因为在第二种情况下您需要检查hasOwnProperty .

当然,如果您只使用一个对象就可以了,您可以完全避免检查和result.push,以防万一使用Object.keys(lookup) 获取数组,但它不会比这更快。

【讨论】:

  • 花费的时间几乎和我的一样。这是jsfiddle.net/MsYGJ/1的比较。其中sberry方法提供了更好的性能。
  • 能否请您将 jsfiddle 与我的方法一起发布作为比较?因为在我的测试中,这种方法肯定比你原来的方法快,而且它似乎也比 sberry 快——但我想仔细检查一下。可能是我遗漏了什么,或者你以不同的方式实现。
  • 好吧,你必须删除第 354 行的警报。在我的 Firefox / Chrome / Safari 上没有它几乎是瞬时的,与其他方法相比;正如我的测试所示。
  • @ZER0 +1 表示您遍历数组的方式。
  • 不是黛比·唐纳,但近 5 年后,由于有人支持,这句话再次出现在我的提要中。 @ZERO 你的小提琴的问题是你只执行一次你的方法,而我的方法被迭代了 100,000 次。这是一个更新版本,显示我的方法快了大约 3 倍:jsfiddle.net/MsYGJ/113。当然,很少需要在这种时间尺度上进行优化。
【解决方案2】:

Underscore.js 非常适合这种事情。您可以使用_.countBy() 获取每个name 的计数:

data = [{"id":11,"name":"ajax","subject":"OR","mark":63},
        {"id":12,"name":"javascript","subject":"OR","mark":63},
        {"id":13,"name":"jquery","subject":"OR","mark":63},
        {"id":14,"name":"ajax","subject":"OR","mark":63},
        {"id":15,"name":"jquery","subject":"OR","mark":63},
        {"id":16,"name":"ajax","subject":"OR","mark":63},
        {"id":20,"name":"ajax","subject":"OR","mark":63}]

_.countBy(data, function(data) { return data.name; });

给予:

{ajax: 4, javascript: 1, jquery: 2} 

对于键的数组,只需使用_.keys()

_.keys(_.countBy(data, function(data) { return data.name; }));

给予:

["ajax", "javascript", "jquery"]

【讨论】:

【解决方案3】:

使用唯一的 Jquery 方法。

var UniqueNames= $.unique(data.DATA.map(function (d) {return d.name;}));

alert($.unique(names));

JSFiddle

【讨论】:

  • 这有问题。如果名称在结果中重复两次以上,则该名称出现两次。例如:如果 ajax 出现 3 次,则结果包含 2 ajax
  • 检查 jsfiddle 它不像你说的那样工作......我已经把所有的名字都写成了“ajax”,结果只显示了一个 Ajax。检查JSFiddle
  • 没有。请在这里查看jsfiddle.net/MsYGJ/3。也比其他方法花费更多时间
【解决方案4】:

这是一个减少的好地方

var uniqueArray = o.DATA.reduce(function (a, d) {
       if (a.indexOf(d.name) === -1) {
         a.push(d.name);
       }
       return a;
    }, []);

【讨论】:

  • 比sberry的方法耗时。
  • 是的,那里的地图没有理由。一个 reduce 就可以做到。您应该知道@sberry 的解决方案不会检查 hasOwnProperty。原型中的杂散属性可能会进入您的列表。
【解决方案5】:

正如您在此处看到的,当您拥有更多价值时,会有更好的方法。

http://jsfiddle.net/MsYGJ/

temp = {}
// Store each of the elements in an object keyed of of the name field.  If there is a collision (the name already exists) then it is just replaced with the most recent one.
for (var i = 0; i < varjson.DATA.length; i++) {
    temp[varjson.DATA[i].name] = varjson.DATA[i];
}
// Reset the array in varjson
varjson.DATA = [];
// Push each of the values back into the array.
for (var o in temp) {
    varjson.DATA.push(temp[o]);
}

这里我们创建了一个以name 为键的对象。该值只是数组中的原始对象。这样做,每个替换都是 O(1) 并且不需要检查它是否已经存在。然后,您将每个值拉出并重新填充数组。

注意
对于较小的数组,您的方法稍微快一些。

注意 2
这不会保留原始顺序。

【讨论】:

  • +1。我有一个 maximum of 100 行,normally 10 。那么我可以采用哪种方法呢?或者我需要同时实现两者并查看差异
  • 完全没问题。你的方法会给我更好的表现。谢谢sberry
【解决方案6】:

首先,我们可以运行map() 函数来获取新数组,其中包含对varjson.DATA 中的每个元素调用提供的函数的结果。

varjson.DATA.map(({name})=>name))

varjson.DATA 得到name 的数组后。我们可以将其转换为一个集合,该集合将丢弃数组的所有重复条目,并应用spread operator 来获取一个唯一名称的数组:

[...new Set(varjson.DATA.map(({name})=>name))]

const varjson = {
  "DATA": [{
      "id": 11,
      "name": "ajax",
      "subject": "OR",
      "mark": 63
    },
    {
      "id": 12,
      "name": "javascript",
      "subject": "OR",
      "mark": 63
    },
    {
      "id": 13,
      "name": "jquery",
      "subject": "OR",
      "mark": 63
    },
    {
      "id": 14,
      "name": "ajax",
      "subject": "OR",
      "mark": 63
    },
    {
      "id": 15,
      "name": "jquery",
      "subject": "OR",
      "mark": 63
    },
    {
      "id": 16,
      "name": "ajax",
      "subject": "OR",
      "mark": 63
    },
    {
      "id": 20,
      "name": "ajax",
      "subject": "OR",
      "mark": 63
    }
  ],
  "COUNT": "120"
}

console.log( [...new Set(varjson.DATA.map(({name})=>name))]);

【讨论】:

  • 请描述您做了哪些更改以及更改的原因,以帮助其他人识别问题并理解此答案
【解决方案7】:

试试这个,MYJSON 将是你的 json 数据。

var mytky=[];
mytky=DistinctRecords(MYJSON,"mykeyname");

function DistinctRecords(MYJSON,prop) {
  return MYJSON.filter((obj, pos, arr) => {
    return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
 })
}

【讨论】:

  • 我试过了,但我没有得到不同键值的数组(属性“mykeyname”的值);我得到了一个具有正确数量元素的数组,并且每个不同的“mykeyname”值都有一个数组,但是 mytky 数组包含整个对象,而不仅仅是键值(例如,像 {"id":11,"name" 之类的对象:来自OP的“ajax”,“subject”:“OR”,“mark”:63},而不仅仅是像11这样的元素)。我对 MYJSON 数组中的 N 个对象迭代 N 平方时间也是对的吗?我是这么认为的: .filter() 迭代所有元素,每次迭代 .map() 都一样,对吧?
【解决方案8】:

试一试:

var distinct_list 

  = data.DATA.map(function (d) {return d[x];}).filter((v, i, a) => a.indexOf(v) === i)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-27
    • 2012-07-15
    • 2021-03-30
    • 2011-01-28
    相关资源
    最近更新 更多