2017-03-05 32 views
1

给定的搜索字符串:如何使用每个对象的所有属性过滤一个对象数组以检查匹配?

Jane

这个数组对象:

[ 
    { 
    name: 'Jane Smith', 
    address: '123 Main St, Boston, MA', 
    telephone: { 
     primary: '1234567890', 
     secondary: '1112223333' 
    } 
    }, 
    { 
    name: 'John Smith', 
    address: '333 Main St, New York, NY 56789', 
    telephone: { 
     primary: '2223334444', 
     secondary: '3334445555' 
    } 
    }, 
    ... 
] 

我们可以通过名字滤镜阵列:

arr.filter(person => person.name.includes(search)) 

大。如果我们只搜索每个对象的name属性,那效果很好。

在对象的所有属性上进行过滤的最佳做法是什么?

我们有权利做这样的事情:

arr.filter(person => 
    person.name.includes(search) || 
    person.address.includes(search) || 
    person.telephone.primary.includes(search) || 
    person.telephone.secondary.includes(search) 
) 

如果有这很乏味,而且容易出错超过几个属性。

如果任何属性的值与搜索字符串匹配,是否有过滤数组的方法?

更新:

这很好地工作的人对象的顶级性能。

.filter(person => { 
    for (let property in person) { 
    return String(person[property]).includes(search) 
    } 
}) 

努力尝试找到通过自身可为对象的属性递归搜索一个很好的解决方案。

+1

你想递归或只顶级做到这一点,您可以通过使用['对... in']对象文本的性质迭代(https://developer.mozilla.org/en -US /文档/网络/的JavaScript /参考/语句/对...的)。 –

+0

@SpencerWieczorek,适用于顶级对象。那么你如何递归测试'obj [prop]'是否是一个对象本身? –

+1

相同的想法,但你会调用递归函数,[看看这个问题](http://stackoverflow.com/questions/2549320/looping-through-an-object-tree-recursively)。 –

回答

1

使用Object.keysArray#some在递归函数(我把它称为deepIncludes),以检查是否有任何财产(或子属性)包括搜索字符串。在这里,我已经使用this存储搜索字符串,因为这可以让你filter你的人数组的语法如下:

let result = array.filter(deepIncludes, 'Search String') 

function deepIncludes (object) { 
 
    return Object.keys(object).some(k => { 
 
    let v = object[k] 
 
    return (v && typeof v == 'object') ? deepIncludes.call(this, v) : String(v).includes(this) 
 
    }) 
 
} 
 

 
let array = [ 
 
    { 
 
    name: 'Jane Smith', 
 
    address: '123 Main St, Boston, MA', 
 
    telephone: { 
 
     primary: '1234567890', 
 
     secondary: '1112223333' 
 
    } 
 
    }, 
 
    { 
 
    name: 'John Smith', 
 
    address: '333 Main St, New York, NY 56789', 
 
    telephone: { 
 
     primary: '2223334444', 
 
     secondary: '3334445555' 
 
    } 
 
    } 
 
] 
 

 
// Usage: 
 
console.log(
 
    array.filter(deepIncludes, '3334445555') //=> [ { name: 'John Smith', ... } ] 
 
)

+1

优秀使用'.some' –

0

最终我选择了接近这个:

function search (obj, text) { 
    for (let prop in obj) { 
    if (String(obj[prop]).includes(text)) { 
     return true 
    } else if (typeof obj[prop] === 'object') { 
     return search(obj[prop], text) 
    } 
    } 
} 

用法:

.filter(person => search(person, text))

更新:

for...in方法不能很好地对我的使用情况下工作。我不知道为什么,但一些键没有搜索。

使用Object.keys方法完美地工作。

function search (obj, text) { 
    return Object.keys(obj).some(k => 
    typeof obj[k] === 'object' 
     ? search(obj[k], text) 
     : String(obj[k]).includes(text) 
) 
} 

(相同的使用)

+0

这段代码有点坏。例如,当搜索'{(a:{b:42}},'b')'时,它会返回true,因为'b'(一个属性)出现在字符串化对象中。也许你应该颠倒两个if语句的顺序。 – 2017-03-05 04:55:23

+0

@torazaburo,是的,我现在注意到了。如果我知道它会更新。另外,出于某种原因,一些(顶级)属性根本没有被搜索到。 –

+0

@torazaburo,出于某种原因,使用Object.keys可以很好地工作。但'因为......在'不。 –

1

您可以使用JSON.stringifyreplacer参数,以此来遍历对象。

function search(obj, str) { 
    var found = false; 

    JSON.stringify(obj, (key, value) => { 
    if (!found && typeof value === 'string' && value.includes(str)) found = true; 
    else return value; 
    }); 

    return found; 
} 
+0

与递归'for ... in'相比,这会提高或减少性能吗? –

+0

如果没有做过基准测试,我会说'for ... in'可能更快,因为这段代码会生成一个JSON字符串(只能将它扔掉),并且在比赛之后还会继续做一些工作被发现。 – 2017-03-05 04:36:25

相关问题