【问题标题】:Remove elements having length less than `n`, in a LARGE sorted array删除 LARGE 排序数组中长度小于“n”的元素
【发布时间】:2015-12-23 23:52:16
【问题描述】:

首先让我解释一下我想要什么。好吧,我有一个这样的排序数组

var arr = ["ab", "abcd", "abdf", "abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"];

现在我需要删除所有字符串长度小于 5 的元素。好的,现在我的意思是,有没有最简单的方法可以找到字符串长度为 4 的元素的索引。喜欢这里的两个元素包含字符串长度4. 但我需要最后一个。如果有可能获得该索引,我可以申请

arr.splice(0, (index+1));

还有一件事,我的原始数组包含 100 万个数据。现在我该如何解决这个问题?

【问题讨论】:

  • 你明白了。循环遍历数组并拼接出您不想要的条目。如果您有一个包含 1,000,000 多个对象的 javascript 数组,那么您可能会遇到更深层次的问题。
  • 你能做一个新的过滤数组吗?还是必须改变原点? arr2=arr.filter(/./.test, /[\w\W]{5}/)
  • 感谢@CollinD。但我真的需要那个。因为接下来他们数组包含 1 个核心数据。所以我需要一种有效的方法来做到这一点。
  • 虽然filter() 是最简单的方法,但使用简单的for循环查找长度为4(或其他)的最后一个元素的索引并使用它做一个切片会更有效.特别是如果元素的数量 > 长度 4 很大。
  • @SudarshanBiswas 即使过滤数组也必须遍历整个数组。这是不可避免的。您可以通过构造一个长度超过 4 的新元素数组来节省时间,但这实际上取决于您的数据。

标签: javascript jquery arrays


【解决方案1】:

您可以使用数组过滤器来删除元素。

var arr = ["ab", "abcd", "abdf", "abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"];
arr = arr.filter(function(item) { 
  return item.length > 4;
});
//["abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"]

我不知道您如何在数组中拥有一百万个项目,但也许您可以尝试在服务器中减少该数组,然后再将其发送到客户端。 (我不知道你的数据到底来自哪里,但对于一个 javascript 数组来说,这是很多数据);

【讨论】:

  • 当你想搜索一个最大长度的元素时,即当元素将在数组的末尾时,这个解决方案会慢很多
  • 一些有趣的性能信息:jsperf.com/provs-sample/4 令人惊讶的是,这种天真的方法似乎要快得多。
【解决方案2】:

虽然filter() 是最简单的方法,但使用简单的 for 循环查找长度为 4(或其他)的最后一个元素的索引并执行单个 slice() 来获得结果会更有效.特别是如果元素数量 > 长度 4 很大。

var arr = ["ab", "abcd", "abdf", "abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"],
    lastIndex = false;

// find the number of elements to be removed
for ( var i = 0; i < arr.length; i++ ) {
    if ( arr[i].length >= 5 ) {
        lastIndex = i;
        break; // break out of the loop
    }
}

// one single splice to get the result
arr.splice(0, lastIndex); 

// arr is now ["abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"]

这是一个performance comparison 的过滤器和循环拼接(上图)策略。正如你所看到的,上面的方法是在过滤器之前的跨越式发展。

【讨论】:

  • 你添加的性能比较只有更少的元素 ~10,它应该至少有 10k+ 元素
  • 另一件事是,当您要搜索具有最大长度的元素时,即当该元素位于数组末尾时,此解决方案会慢得多,因此您的 performance test 不会在这个时候证明什么
  • @Tushar - 这是一个包含几千个元素的测试,从 length:2 到 length:11 按长度排序。正如您所说,当要删除的元素数量非常大(即匹配非常接近或位于数组末尾的元素)时 - 本机过滤器更快。但在所有其他情况下,循环和切片速度更快,因为它不涉及遍历整个数组。
【解决方案3】:

好消息是数组按长度排序,坏消息是数组包含 100,000 多个元素。

字符串上的正则表达式比遍历数组更快(特别是在 100k+ 元素的情况下)

您可以使用正则表达式获取具有指定长度的最后一个元素,然后您可以使用索引在数组上使用splice

  1. 使用join将数组转换为字符串
  2. 使用正则表达式提取所有长度为n的字符串
  3. 从匹配集中获取最后一个元素
  4. 从原始数组中获取该元素的最后一个索引
  5. splice 使用这个索引的原始数组

Demo

var arr = ["ab", "abcd", "abdf", "abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"];

var matches = arr.join(",").match(/\b[a-z]{5}\b/ig) || [];

arr.splice(0, arr.lastIndexOf(matches[matches.length - 1]) + 1);

console.log(arr);
document.write(arr);

正则表达式解释

  1. \b: 字边界
  2. [a-z]: 匹配所有字母
  3. {n}: 准确匹配上一个课程 n 次
  4. i:区分大小写的匹配
  5. g:全局,获取所有匹配项

二分搜索

您还可以使用二分搜索将数组拆分为两个相等的子数组,并在各个子数组中搜索具有指定长度的最后一个元素。然后用这个元素获取它的索引,然后拼接原始数组。

搜索算法由Binary Search in Javascript提供

var arr = ["ab", "abcd", "abdf", "abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"];

var copy = arr.slice();

function binarySearch(arr, len) {
  var mid = Math.floor(arr.length / 2);
  console.log(arr[mid], len);

  if (arr[mid].length === len && arr[mid + 1].length === len) {
    console.log('match', arr[mid], len);
    return binarySearch(arr.splice(mid));
  } else if (arr[mid].length === len) {
    return arr[mid];
  } else if (arr[mid].length < len && arr.length > 1) {
    console.log('mid lower', arr[mid], len);
    binarySearch(arr.splice(mid, Number.MAX_VALUE), len);
  } else if (arr[mid].length > len && arr.length > 1) {
    console.log('mid higher', arr[mid], len);
    binarySearch(arr.splice(0, mid), len);
  } else {
    console.log('not here', len);
    return -1;
  }
}

var result = binarySearch(copy, 5);

arr.splice(0, arr.lastIndexOf(result) + 1);

console.log(arr);
document.write(arr);

【讨论】:

  • 注意:如果没有长度正好为 5 的元素,此代码将出错。此外,测试用例 arr = ["abcde","ab","a","abf"] 的输出不正确,除非我对问题的理解不正确。
  • @CollinD 感谢指出错误,防止错误
  • 忽略我对错误输出的评论。我错过了指定数组已经按长度排序的部分。
【解决方案4】:

试试这样的

  1. 删除所有长度小于 5 的元素

       var arrFiltered = arr.filter(function(element){ return element.length>=5});
    
  2. 获取长度为 4 的最后一个元素的索引

       var lastId = 0;
       var filteredElements = arr.filter(function(e){ 
                  return e.length === 4;
       };
    
       lastId = filteredElement[filteredElement.length-1]?arr.indexOf(filteredElement.pop());
    

【讨论】:

  • 当你想搜索一个最大长度的元素时,即当元素将在数组的末尾时,这个解决方案会慢很多
【解决方案5】:

尝试使用do.. while循环

do {
  arr.splice(0,1)
} while (arr[0].length < 5)

【讨论】:

  • 当你想搜索一个最大长度的元素时,即当元素将在数组的末尾时,这个解决方案会慢很多
【解决方案6】:

我们也可以像下面这样使用jquery的.grep函数

var arr = ["ab", "abcd", "abdf", "abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"],

            arr=$.grep(arr,function (obj,i){
                return obj.length > 4
            })
            console.log('value is'+arr);

一般也用于从数组中过滤

【讨论】:

  • 当你想搜索一个最大长度的元素时,即当元素将在数组的末尾时,这个解决方案会慢很多
【解决方案7】:

按照 Tushar 的评论,如果对数组进行排序,则有一种更有效的 lodash 方法:

arr = _.takeWhile(arr, function(element){ return element.length < 5; });

--- 旧方法 ---

您可以使用lodash 来做这个漂亮、干净和简单的事情:

arr = _.filter(arr, function(element){return element.length < 5; };

var arr = ["ab", "abcd", "abdf", "abcdd", "abcdd", "abcdfd", "abcdsss", "abcdefgh", "abcdsdsdsds"];

// arr = _.filter(arr, function(element){return element.length < 5; });
arr = _.takeWhile(arr, function(element){ return element.length < 5; });

alert('filtered array: ' + arr);
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"&gt;&lt;/script&gt;

【讨论】:

  • 第一件事 lodash 没有被标记,OP 没有提到使用 loadash 的解决方案。第二件事是当你想搜索一个最大长度的元素时,即当元素位于数组的末尾时,这个解决方案会慢得多
  • 您对效率的看法是正确的,我将发布一个修改后的解决方案,至于lodash,不确定我是否理解不被提及的相关性。
猜你喜欢
  • 1970-01-01
  • 2013-01-31
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 2018-12-07
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
相关资源
最近更新 更多