对象数组中的二进制搜索 javascript

binary search in array of object javascript

我有一个对象数组:

array = [
  {
    name:'alex',   
    number:36783712773
  },
  {
    name:'gabe',   
    number:99938873,
  },
and so on like this
]

我知道二分查找的基本概念及其工作原理,但是互联网上的大多数示例都处理一个数字数组,所以我不知道如何按名称和 phone 通过数组进行搜索对象。

我可以从后端进行搜索,但我不想为 javascript 中可以轻松处理的事情进行不必要的 HTTP 调用。

提前致谢。

下面是二分查找的实现。

在此答案的先前版本中,生成测试用例时存在巨大错误。与线性搜索相比,更新版本显示了二进制搜索的优势,在使用小数组时已经如此。

这是一个脚本,用于计算对对象数组执行线性搜索和二分搜索的时间。首先是 10 个对象的数组,然后是 100、1000,最后是 10 000:

function binarySearch(array, target) {
    let lo = 0, hi = array.length;
    while (lo < hi) {
        let mi = (lo + hi) >> 1;
        let diff = target - array[mi].number;
        if (diff === 0) return array[mi];
        else if (diff < 0) hi = mi;
        else lo = mi + 1;
    }
}

function linearSearch(array, target) {
    return array.find(o => o.number === target);
}

function test(searchFunc, array, searchValues, times) {
    let accTime = 0;
    for (let time = 0; time < times; time++) { // Time the execution several times
        let now = performance.now();
        for (let number of searchValues) {
            let match = searchFunc(array, number);
            if (!match) throw "err";
        }
        accTime += performance.now() - now;
    }
    return accTime / times; // ... and take average
}

for (let length = 10; length < 1e5; length *= 10)
{
    let array = Array.from({length}, (_, number) =>
        ({ name: "alex", ismember: true, number: number * 100 + 13 })
    );
    let searchValues = Array.from({length: 10000}, () =>
        Math.floor(length * Math.random()) * 100 + 13
    );
    // First a dry run
    let linearSearchTime = test(linearSearch, array, searchValues, 2);
    let binarySearchTime = test(binarySearch, array, searchValues, 2);
    // The real run
    linearSearchTime = test(linearSearch, array, searchValues, 5);
    binarySearchTime = test(binarySearch, array, searchValues, 5);
    console.log({length, binarySearchTime, linearSearchTime});
}

不同的可搜索属性

如果您想有时按一个 属性 使用二分搜索,有时按另一个 属性,那么您需要创建单独的“索引”来引用您的数据,每个索引都按相关 属性.

例如:

let data = [
    { name: "alex", number: 13 },
    { name: "helen", number: 10 },
    { name: "zoe", number: 11 },
    { name: "willy", number: 12 },
];

let index = Object.fromEntries(["name", "number"].map(prop => [
    prop,
    data.map(o => [o[prop], o])
        .sort(([a], [b]) => (a > b) - (a < b))
]));

function binarySearch(array, target) {
    let lo = 0, hi = array.length;
    while (lo < hi) {
        let mi = (lo + hi) >> 1;
        let key = array[mi][0]; 
        if (key === target) return array[mi][1]; // the actual data
        else if (key > target) hi = mi;
        else lo = mi + 1;
    }
}

// demo
console.log(binarySearch(index.name, "willy"));
console.log(binarySearch(index.name, "zoe"));
console.log(binarySearch(index.name, "alex"));
console.log(binarySearch(index.name, "helen"));
console.log(binarySearch(index.number, 13));
console.log(binarySearch(index.number, 12));
console.log(binarySearch(index.number, 11));
console.log(binarySearch(index.number, 10));