Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在JavaScript中查找数组中相邻子数组的优雅方法?_Javascript_Arrays - Fatal编程技术网

在JavaScript中查找数组中相邻子数组的优雅方法?

在JavaScript中查找数组中相邻子数组的优雅方法?,javascript,arrays,Javascript,Arrays,我想写一个函数,从给定的起始索引中查找给定数组中的一个连续子数组,如果找到子数组,则返回该数组中该子数组的索引;如果未找到,则返回-1。这类似于String.indexOf,但用于数组和子数组,而不是字符串和子字符串 这是我的工作代码: var find_csa = function (arr, subarr, from_index) { if (typeof from_index === 'undefined') { from_index = 0; }

我想写一个函数,从给定的起始索引中查找给定数组中的一个连续子数组,如果找到子数组,则返回该数组中该子数组的索引;如果未找到,则返回-1。这类似于
String.indexOf
,但用于数组和子数组,而不是字符串和子字符串

这是我的工作代码:

var find_csa = function (arr, subarr, from_index) {
    if (typeof from_index === 'undefined') {
        from_index = 0;
    }

    var i, found, j;
    for (i = from_index; i < 1 + (arr.length - subarr.length); ++i) {
        found = true;
        for (j = 0; j < subarr.length; ++j) {
            if (arr[i + j] !== subarr[j]) {
                found = false;
                break;
            }
        }
        if (found) return i;
    }
    return -1;
};
我的代码通过了测试,但正如您所看到的,它在内部循环中使用了一个布尔值
found
,这只是我从嵌套循环继续外部循环的一种杂乱的特殊方式。有没有更干净的书写方法?我研究过,但目前这是一项实验技术,所以我不能使用它。我想要一个在大多数浏览器中都能工作的方法。我知道Mozilla页面上有一个“polyfill”代码段,但它甚至比我当前的代码还要长,而且由于函数调用的原因,它会变得更慢,所以我宁愿避免使用它

我对这个函数的主要目标是性能(子数组将非常小,所以我认为使用or有点过分),然后我的次要目标是实现的优雅。考虑到这两个目标,我想知道是否有更好的方法来编写此代码,或者是否有任何JavaScript特性或函数可以帮助我避免使用
found
boolean


JSFiddle如果它对任何人都有帮助:

这和你的一样,只是稍微美化了一下(至少对我的美学而言):

var find\u csa=函数(arr、subar、from\u索引){
from|index=from|index | 0;
变量i,发现,j;
var last_check_index=阵列长度-子阵列长度;
var subar_length=subar.length;
位置\u环:
对于(i=从索引;i
是否有任何JavaScript特性或函数可以帮助我避免使用
found
boolean

是的,您可以在外环上使用:

function find_csa(arr, subarr, from_index) {
    var i = from_index >>> 0,
        sl = subarr.length,
        l = arr.length + 1 - sl;

    loop: for (; i<l; i++) {
        for (var j=0; j<sl; j++)
            if (arr[i+j] !== subarr[j])
                continue loop;
        return i;
    }
    return -1;
}
函数find_csa(arr、SubAR、from_索引){
var i=来自指数>>>0,
sl=分段长度,
l=arr.length+1-sl;

循环:对于(;i而言,可以使用数组方法将内部循环减少为一条直线:

或(ES6建议书):


但这可能只是一个好奇或教育性的例子,除非您不关心性能。

在循环中,您可以消除
found
变量,避免继续这样:

for (j = 0; j < subarr.length; ++j) {
    if (arr[i + j] !== subarr[j]) break;
}
/*
 * the above loop breaks in two cases:
 * normally: j === subarr.length
 * prematurely: array items did not match
 * we are interested in kowing if loop terminated normally
 */
if (j === subarr.length) return i;

在阅读基于zerkms主张的最初讨论时,我很有兴趣尝试使用JSON.stringify的解决方案,尽管有一些不利的意见

然后我终于找到了一个解决方案,它正确地通过了所有测试。
可能不是更快的方法,但肯定是最短的方法:

var find_csa = function (arr, subarr, from_index) {
  var start=from_index|0,
      needle=JSON.stringify(subarr),
      matches=JSON.stringify(arr.slice(start)).
      match(new RegExp('^\\[(.*?),?'+
        needle.substr(1,needle.length-2).replace(/([\[\]])/g,'\\$1')
      ));
  return !!matches?(matches[1].length?matches[1].split(',').length:0)+start:-1;
}
上面的代码接受Shashank建议的数组数组,但无法处理包含逗号的项

因此,我开发了另一个也接受逗号的解决方案(感谢Steven Levithan关于
while(str!=(str=str.replace(regexp,replacement));

但这只是为了好玩,因为:

  • 代码不是那么短,现在…叹气
  • 它可能会消耗大量的CPU时间
  • 它不能正确处理空项(它们被忽略)
  • 我怀疑(并没有深入挖掘:-)复杂对象作为项目可能会失败
不管怎样,这是:

var find_csa = function (arr, subarr, from_index) {
  var start=from_index|0,
      commas=new RegExp('(?:(\')([^,\']+),([^\']+)\'|(")([^,"]+),([^"]+))"'),
      strip_commas='$1$2$3$1$4$5$6$4',
      haystack=JSON.stringify(arr.slice(start)),
      needle=JSON.stringify(subarr).replace(/^\[(.*)\]$/,'$1');
  while(haystack!=(haystack=haystack.replace(commas,strip_commas)));
  while(needle!=(needle=needle.replace(commas,strip_commas)));
  matches=haystack.match(new RegExp('^\\[(.*?),?'+needle.replace(/([\[\]])/g,'\\$1')));
  return !!matches?(matches[1].length?matches[1].split(',').length:0)+start:-1;
}

1.
JSON.stringify
2.
array.prototype.slice
不与
'
连接,而是与
连接,
,String.indexOf仍然有效,但它将避免解释
[2,11,5]
[21,15]
同上thing@zerkms,我可以看到JSON.stringify正在寻找一个连续子数组的存在,但是你知道如何检索它的索引吗?我猜你必须用逗号或其他什么来分割。但是你会回到平方1。在你的2号方法中,我看不到
Array.prototype.slice
ld帮助。我知道你可以使用它来使用
call
将字符串转换为数组,但这不是问题所在。@Shashank我想出了一种不同的方法。看看它是否满足你的要求need@slebetman很好…但我想要原始数组中的子数组索引。而不是字符串中的子字符串索引…
[12,44,65]。连接(',')
生成
'12,44,65'
,但随后搜索
[44,65]。连接(','))
使用
String.indexOf
可以得到3,因为它从第一个字符开始,而不是1。我从我的问题中删除了
数组.prototype.join
方法,因为我认为它不适用于转换为不同长度字符串(例如9999)的值。我喜欢这个答案。我不知道JS.Th中有标签at当然会稍微清理一下我的代码。虽然它警告不要使用它们。这被认为是不好的做法吗?-tl;dr:如果程序在使用标签时更容易理解和更简洁,那么就使用标签(但通常不是这样)很好,但我有两个问题,你使用的
>
语法是什么?这是设置默认参数值的标准方法吗?使用标签也被认为是不好的做法吗?我问这个问题的原因是因为它说避免在这里使用它们:不标准,
>0
是一种说“转换为整数”的老套方法.
x>>>y
是“将
x
向右移动
y
位”;如果你移动0位,这和你以前做的一样,但是由于
>
只对整数起作用,你会得到强制为整数值的副作用。这可能是最快的方法,与
x
当然,假设你的参数已经是整数,如果你知道调用者会遵守约定,那么更快@Shashank:The
>
无符号位移位用于。标签是完全安全的,似乎有些人不了解它们是如何工作的,并试图避免使用此功能。@Bergi我不认为这是因为pe
if(subarr.every( (e, j) => (e === arr[i + j]) ))
    return i;
for (j = 0; j < subarr.length; ++j) {
    if (arr[i + j] !== subarr[j]) break;
}
/*
 * the above loop breaks in two cases:
 * normally: j === subarr.length
 * prematurely: array items did not match
 * we are interested in kowing if loop terminated normally
 */
if (j === subarr.length) return i;
function find_csa(arr, subarr, from_index) {
    from_index |= 0;
    if (subarr.length === 0) {
        return from_index;
    }
    var haystack = "," + arr.slice(from_index).join(",") + ",",
        needle = "," + subarr.join(",") + ",",
        pos = haystack.indexOf(needle);
    if (pos > 0) {
        pos = haystack.substring(1, pos).split(",").length + from_index;
    }
    return pos;
}
console.log("All tests should return true");
console.log(find_csa([1, 2, 3, 4, 5], [1, 2, 3]) === 0);
console.log(find_csa([1, 2, 3, 4, 5], [2, 3, 4]) === 1);
console.log(find_csa([1, 2, 3, 4, 5], [5]) === 4);
console.log(find_csa([1, 2, 3, 4, 5], [6]) === -1);
console.log(find_csa([1, 2, 3, 4, 5], [1, 3]) === -1);
console.log(find_csa([6, 6, 6, 7], [6, 6, 7]) === 1);
console.log(find_csa([1, 2, 3, 4, 5], []) === 0);
console.log(find_csa([3, 4, 3, 4, 3, 4], [3, 4, 3], 1) === 2);
console.log(find_csa([1, 2, 3, 4, 5], [], 1) === 1);
var find_csa = function (arr, subarr, from_index) {
  var start=from_index|0,
      needle=JSON.stringify(subarr),
      matches=JSON.stringify(arr.slice(start)).
      match(new RegExp('^\\[(.*?),?'+
        needle.substr(1,needle.length-2).replace(/([\[\]])/g,'\\$1')
      ));
  return !!matches?(matches[1].length?matches[1].split(',').length:0)+start:-1;
}
var find_csa = function (arr, subarr, from_index) {
  var start=from_index|0,
      commas=new RegExp('(?:(\')([^,\']+),([^\']+)\'|(")([^,"]+),([^"]+))"'),
      strip_commas='$1$2$3$1$4$5$6$4',
      haystack=JSON.stringify(arr.slice(start)),
      needle=JSON.stringify(subarr).replace(/^\[(.*)\]$/,'$1');
  while(haystack!=(haystack=haystack.replace(commas,strip_commas)));
  while(needle!=(needle=needle.replace(commas,strip_commas)));
  matches=haystack.match(new RegExp('^\\[(.*?),?'+needle.replace(/([\[\]])/g,'\\$1')));
  return !!matches?(matches[1].length?matches[1].split(',').length:0)+start:-1;
}