【问题标题】:Find closest array index查找最近的数组索引
【发布时间】:2018-06-05 08:59:46
【问题描述】:

我正在处理一个“events”数组,其中数组的key 是事件的Unix Timestamp。换句话说,假设我们在 JS 中有以下 event 对象数组:

var MyEventsArray=[];
MyEventsArray[1513957775]={lat:40.671978333333, lng:14.778661666667, eventcode:46};
MyEventsArray[1513957845]={lat:40.674568332333, lng:14.568661645667, eventcode:23};
MyEventsArray[1513957932]={lat:41.674568332333, lng:13.568661645667, eventcode:133};
and so on for thousands rows...

数据通过 Ajax 调用发送并在 JSON 中编码以使用 JS 进行处理。收到数据集后,我有另一个 Unix 时间戳,比如说 1513957845,来自另一个来源,我想找到当时发生的事件......这很容易我只需要从具有给定索引(上面列表中的第二个)。 现在的问题是:想象一下没有找到给定的索引(假设我们正在寻找 UXTimestamp=1513957855)并且这个索引在数组中不存在但我想取最近的索引(在上面的示例我将采用元素 MyEventsArray[1513957845],因为它的索引 1513957845 最接近 1513957855)。我该怎么做才能获得这个结果? 我的困难在于处理数组索引,因为当我收到数组时我不知道索引从哪里开始。

机器将如何处理这种情况? 机器是否会为放置在每行之间的虚拟/空元素分配(和浪费)内存,或者编译器是否有某种能力来构建自己的索引并优化空间?换句话说:像我们正在做的那样使用索引是否安全,或者最好将数组分配为:

var MyEventsArray=[];
MyEventsArray['1513957775']={lat:40.671978333333, lng:14.778661666667, eventcode:46};
MyEventsArray['1513957845']={lat:40.674568332333, lng:14.568661645667, eventcode:23};
MyEventsArray['1513957932']={lat:41.674568332333, lng:13.568661645667, eventcode:133};
and so on for thousands rows...

在这种情况下,键和索引明显不同,因此尽管我们不知道键值,但可以使用 MyArray[0] 获取第一个元素。这种方法在内存方面是否更昂贵(这里我们必须保存索引和键)还是编译器的效果相同?

【问题讨论】:

    标签: javascript arrays json ajax associative-array


    【解决方案1】:

    您可以使用Array#some,如果增量大于上一个增量,则允许退出迭代。

    var array = [];
    array[1513957775] = { lat: 40.671978333333, lng: 14.778661666667, eventcode: 46 };
    array[1513957845] = { lat: 40.674568332333, lng: 14.568661645667, eventcode: 23 };
    array[1513957932] = { lat: 41.674568332333, lng: 13.568661645667, eventcode: 133 };
    
    var key = 0,
        search = 1513957855;
    
    Object.keys(array).some(function (k) {
        if (Math.abs(k - search) > Math.abs(key - search)) {
            return true;
        }
        key = k;
    });
    
    console.log(key);

    【讨论】:

    • Object.keys 不能保证以任何特定顺序返回键,因此此优化依赖于实现细节。
    • @JLRishe,在lealet ES2015 的较新系统中具有标准,整数属性首先排序,因此不需要排序,因为您以正确的顺序进行迭代。一个更快的方法可能是使用二分搜索。
    • 谢谢。我没有意识到他们在 ES2015 中对其进行了标准化。
    【解决方案2】:

    MyEventsArray[1513957775]MyEventsArray['1513957775'] 之间没有区别。归根结底,数组索引只是属性名,而属性名是字符串。

    关于这些稀疏索引是否会导致数百万个空单元被分配的问题,不,这不会发生。稀疏数组只存储您放入其中的内容,而不是空白空间。

    如果你想快速找到一个键,你可以获取一个键的数组,对它们进行排序,然后找到你想要的:

    var MyEventsArray=[];
    MyEventsArray[1513957775]={lat:40.671978333333, lng:14.778661666667, eventcode:46};
    MyEventsArray[1513957845]={lat:40.674568332333, lng:14.568661645667, eventcode:23};
    MyEventsArray[1513957932]={lat:41.674568332333, lng:13.568661645667, eventcode:133};
    
    var target = 1513957855;
    
    var closest= Object.keys(MyEventsArray)
                       .map(k => ({ k, delta: Math.abs(target - k) }))  
                       .sort((a, b) => a.delta - b.delta)[0].k;
    
    console.log(closest);

    【讨论】:

    • 出色的解决方案,我低估了 Object.keys().map。这正是我想要的。
    【解决方案3】:

    您可以使用Object.keys(MyEventsArray) 获取键的数组(奇怪地表示为字符串);然后你可以遍历它并找到最接近的匹配。

    var MyEventsArray=[];
    MyEventsArray[1513957775]={lat:40.671978333333, lng:14.778661666667, eventcode:46};
    MyEventsArray[1513957845]={lat:40.674568332333, lng:14.568661645667, eventcode:23};
    MyEventsArray[1513957932]={lat:41.674568332333, lng:13.568661645667, eventcode:133};
    Object.keys(MyEventsArray)
    

    ["1513957775", "1513957845", "1513957932"]

    参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

    【讨论】:

    • 很好 - 那么您可以 .map 针对该键数组为每个条目添加第二个属性,该属性由键数组的值和搜索值之间的绝对差组成.. 然后对返回的映射数组进行排序差异上升抓住了第一个条目。我喜欢这个Object.keys(MyEventsArray)
    猜你喜欢
    • 2016-07-19
    • 1970-01-01
    • 2017-03-15
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2018-07-31
    • 1970-01-01
    • 2010-11-12
    相关资源
    最近更新 更多