搜索 JavaScript 对象

IT技术 javascript
2021-02-25 04:32:05

我有一个这样的 JavaScript 对象:

[{
    name : "soccer",
    elems : [
        {name : "FC Barcelona"},
        {name : "Liverpool FC"}
    ]
},
{
    name : "basketball",
    elems : [
        {name : "Dallas Mavericks"}
    ]
}]

现在我想在浏览器中搜索这个 JavaScript 对象。搜索“FC”应该给我这样的东西:

[
    {name : "FC Barcelona"},
    {name : "Liverpool FC"}
]

如何快速做到这一点?是否有任何 JavaScript 库?

6个回答

您可能喜欢使用 jLinq(个人项目)

http://hugoware.net:4000/Projects/jLinq

像 LINQ 一样工作,但适用于 JSON,它允许您根据需要扩展和修改它。已经有一堆预构建的方法来检查值和范围。

似乎唯一有用的答案是引用第三方库 - 这是您的本机 javascript 解决方案。对于只想要几行代码而不是堆栈的任何人:

功能:

Array.prototype.findValue = function(name, value){
   var array = map(this, function(v,i){
        var haystack = v[name];
        var needle = new RegExp(value);
        // check for string in haystack
        // return the matched item if true, or null otherwise
      return needle.test(haystack) ? v : null;
   });
  return array;
}

原生.map()函数:

map = function(array, mapFunction) {
      var newArray = new Array(array.length);
      for(var i = 0; i < array.length; i++) {
        newArray[i] = mapFunction(array[i]);
      }
      return newArray;
}

你的对象:

(从您发布的贬义词中略读):

myObject = {
        name : "soccer",
        elems : [
            {name : "FC Barcelona"},
            {name : "Liverpool FC"}
        ]
    },
    {
        name : "basketball",
        elems : [
            {name : "Dallas Mavericks"}
        ]
    }

用途:

(这将在 myObject.elems 数组中搜索与“FC”匹配的“名称”)

var matched = myObject.elems.findValue('name', 'FC');
console.log(matched);

结果 - 检查您的控制台:

[Object, Object, findValue: function]
0: Object
name: "FC Barcelona"
__proto__: Object
1: Object
name: "Liverpool FC"
__proto__: Object
length: 2
__proto__: Array[0]

试试 jOrder。http://github.com/danstocker/jorder

它针对 JS 中大型(数千行)表的快速 O(logn) 搜索和排序进行了优化。

与此处的大多数答案所基于的数组迭代相反,jOrder 使用索引来过滤数据。只是给您一个想法,在 1000 行表上的自由文本搜索比迭代快大约 100 倍。桌子越大,你得到的比例就越好。

但是 jOrder 无法处理您的示例数据的格式。但是如果你像这样重新格式化它:

var teams =
[
{ sport : "soccer", team: "FC Barcelona" },
{ sport : "soccer", team: "Liverpool FC" },
{ sport : "basketball", team : "Dallas Mavericks"}
]

您可以通过首先设置一个 jOrder 表来获得所需的结果:

var table = jOrder(teams)
    .index('teams', ['team'], { grouped: true, ordered: true, type: jOrder.text });

然后对其进行搜索:

var hits = table.where([{ team: 'FC' }], { mode: jOrder.startof });

你会得到你需要的两行。而已。

执行此操作的直接方法是简单地迭代对象的每个属性并将测试函数应用于它们(在本例中为value.contains("FC"))。

如果你想让它运行得更快,你要么需要实现某种缓存(可以在任何查询之前在后台热切地填充),或者可能预先计算各种流行测试函数的结果。

@Nosredna:是的,预处理是绝对可能的。
2021-04-29 04:32:05
我想比 O(n) 更快。我想过像en.wikipedia.org/wiki/Trie这样的东西,但如果没有必要,我不想自己写。
2021-05-01 04:32:05
@Juri,您愿意将对象预处理为不同的结构,还是要按原样使用对象?当然,从一种结构转换到另一种结构是有成本的。如果您要对同一数据进行大量搜索,这可能是值得的。
2021-05-05 04:32:05
@Juri - 根据定义,如果一个对象包含有关其他对象的一些信息,则只能比 O(n) 快;也就是说,给定在一个对象上运行测试函数的输出,您至少可以推导出其他一些对象的输出。此外,为什么你想要比 O(n) 快?您知道您需要对大量对象具有良好的渐近性能吗?我怀疑你实际上没有。
2021-05-10 04:32:05

您可以使用针对序列化 JSON 字符串执行的正则表达式来执行此操作:

var jsonString = "[{ name : \"soccer\", elems : [ {name : \"FC Barcelona\"}"
    +", {name : \"Liverpool FC\"}]},{name : \"basketball\",elems : ["
    +"{name : \"Dallas Mavericks\"} ]}]";

var pattern = /\s*([\w\d_]+)\s*:\s*((\"[^\"]*(your pattern here)[^\"]*\")|(\'[^\']*(your pattern here)[^\']*\'))\s*/g;

var foundItems = [];
var match;
while(match = pattern.exec(jsonString)){
  foundItems.push(match[0]);
}

var foundJSON = "[{" + foundItems.join("}, {") + "}]";
var foundArray = eval(foundJSON);

我还没有测试过这个循环部分,但是通过 firebug 中的简单测试,Regex 似乎对我来说效果很好。