Javascript 在重复模式中查找第二个元素

Javascript 在重复模式中查找第二个元素,javascript,functional-programming,ramda.js,Javascript,Functional Programming,Ramda.js,重复“i”后接“i”和/或“t”的数据 data = ['i','t','t','i','i','t','t','t'] 正在尝试检索模式['i','t','t']中最后一个't'的索引: [2,6] // ['i','t','t','i','i','t','t','t'] # position of the returned 't's // _______ ^ _______ ^ 我正在寻找仅使用纯函数的非递归解决方案,例如使用ramdajs 尝试使用reduc

重复“i”后接“i”和/或“t”的数据

data = ['i','t','t','i','i','t','t','t']
正在尝试检索模式['i','t','t']中最后一个't'的索引:

[2,6] // ['i','t','t','i','i','t','t','t'] # position of the returned 't's
      //   _______ ^       _______ ^
我正在寻找仅使用纯函数的非递归解决方案,例如使用ramdajs

尝试使用reduce和transduce,但至今未成功。

您只需执行for循环并检查数组的最后一个值即可:

var数据=['i'、't'、't'、'i'、'i'、't'、't'、't']; var位置=新数组; forvar i=2;i var数据=['i'、't'、't'、'i'、'i'、't'、't'、't']; var位置=新数组; forvar i=2;i 数据=['i','t','t','i','i','t','t','t','t'] var newData=data.reducefunction acc,项目,索引{ //检查当前元素是否为't',其前面的项是否为'i','t'' 如果项=='t'和数据[索引-1]=='i'和数据[索引-2]=='t'{ 附件项目 } 返回acc; }, []; console.lognewData;//['t','t']您可以使用一个简单的条件来完成

数据=['i','t','t','i','i','t','t','t','t'] var newData=data.reducefunction acc,项目,索引{ //检查当前元素是否为't',其前面的项是否为'i','t'' 如果项=='t'和数据[索引-1]=='i'和数据[索引-2]=='t'{ 附件项目 } 返回acc; }, [];
console.lognewData;//['t','t']您可以使用带有临时数组的嵌套方法来检查不同起点的相同模式。此建议使用任意长度的模式,并返回预定义模式的索引

这个解决方案的特点显然是纯Javascript


.作为控制台包装{max height:100%!important;top:0;}您可以使用带有临时数组的嵌套方法来检查不同起点的相同模式。此建议使用任意长度的模式,并返回预定义模式的索引

这个解决方案的特点显然是纯Javascript

.作为控制台包装{最大高度:100%!重要;顶部:0;} **无负指数:**

const matchMaker = () => {
    let memo = [‘a’, ‘b’];
    return (c, i, d) => {
        memo.unshift(c);
        return memo[1] + memo[2] + c === 'itt';
    }
};

data.filter(matchMaker());
**无负指数:**

const matchMaker = () => {
    let memo = [‘a’, ‘b’];
    return (c, i, d) => {
        memo.unshift(c);
        return memo[1] + memo[2] + c === 'itt';
    }
};

data.filter(matchMaker());

一种方法是迭代数据列表的3元素滑动窗口,然后跟踪与模式['i','t','t']相等的任何子列表的位置

常量数据=['i'、't'、't'、'i'、'i'、't'、't'、't'] 常量isPattern=R.equals['i','t','t'] 常量reduceWithIdx=R.addIndexR.reduce const positions=reduceWithIdxidxs,next,idx=> 下一个是什么?R.appendidx+2,idxs:idxs ,[],右光圈3,数据 控制台。日志位置
一种方法是迭代数据列表的3元素滑动窗口,然后跟踪与模式['i','t','t']相等的任何子列表的位置

常量数据=['i'、't'、't'、'i'、'i'、't'、't'、't'] 常量isPattern=R.equals['i','t','t'] 常量reduceWithIdx=R.addIndexR.reduce const positions=reduceWithIdxidxs,next,idx=> 下一个是什么?R.appendidx+2,idxs:idxs ,[],右光圈3,数据 控制台。日志位置 函数getPatternarr,p{ var r=[], dir=[]; 对于arr条目的let[i,v]{ dir=dir.concati.filterfunctionx{ 如果v==p[i-x]&&i-x==p.length-1{ r、 浦西; 返回false; } 返回v==p[i-x]; } }; 返回r; } loggetPattern['i',t',t',i',i',t',t',t'],['i',t',t']; loggetPattern['i',t','i','t','t','i','t','t','t','t'],['i','t','t']; loggetPattern['a','b','a','b','b','a','b','c','d'],['a','b','c']; .作为控制台包装{最大高度:100%!重要;顶部:0;} 函数getPatternarr,p{ var r=[], dir=[]; 对于arr条目的let[i,v]{ dir=dir.concati.filterfunctionx{ 如果v==p[i-x]&&i-x==p.length-1{ r、 浦西; 返回false; } 返回v==p[i-x]; } }; 返回r; } loggetPattern['i',t',t',i',i',t',t',t'],['i',t',t']; loggetPattern['i',t','i','t','t','i','t','t','t','t'],['i','t','t']; loggetPattern['a','b','a','b','b','a','b','c','d'],['a','b','c'];
.as console wrapper{max height:100%!important;top:0;}以防任何人希望看到示例而不使用不使用“向前看”或“向后看i+1或i-2”等的库

我认为它的工作原理与Ramda方法类似,但我选择在 ame循环:

减少每一步 取阵列中与阵列长度匹配的部分 检查它是否与图案相同 如果是,则将节中最后一个元素的索引添加到reduce的结果中 代码,其中模式和数据都是字符串数组:

const findPattern = (pattern, data) => data.reduce(
  (results, _, i, all) => 
    // Check if a slice from this index equals the pattern
    arrEqual(all.slice(i, i + pattern.length), pattern)
      // Add the last index of the pattern to our results
      ? (results.push(i + pattern.length - 1), results)
      // or, return what we had
      : results, 
    []);

// Utility method to check array equality
const arrEqual = (arr1, arr2) =>
  arr1.length === arr2.length &&
  arr1.every((x, i) => x === arr2[i]);
我在几个数据集上进行了测试,认为它满足所有要求:

const findPattern=模式,data=>data.reduce 结果,i,all=> arrEqualall.slicei,i+pattern.length,pattern ? pushresults,i+模式长度-1 :结果, []; 常数arrqual=arr1,arr2=> arr1.length==arr2.length&& arr1.everyx,i=>x==arr2[i]; 常量push=xs,x=>xs.pushx,xs; //对于字符串模式,我们还可以执行以下操作: //常量arrqual=arr1,arr2=>arr1.join==arr2.join; //测试用例 常量数据集=[ //我标记了一个匹配的索引 //[i]标记应返回的最后一个匹配索引 //|标志着一个新的开始 {模式:[i,t,t],输入:['i','t','t','i','i','t','t','t','t'],输出:[2,6]}, // |0 1 [2]| 3 -4 5 [6]| 7 {pattern:[i,t],输入:['i','t','i','t','t','i','t','t','t','t','t'],输出:[1,3,7]}, // |0 [1]|2 [3]| 4 | 5 |6 [7]| 8 | 9 {pattern:[i,t,t],输入:['i','t','i','t','t','i','i','t','t','t','t'],输出:[4,8]}, // |0 1|2 3 [4]| 5 |6 7 [8]| 9 {模式:[i,t,i],输入:['i','t','i','t','i','t','i','t','i','t','i','t'],输出:[2,4,6,8]] // |0 1 [2]| |6 7 [8]| 9 // |2 3 [4] // |4 5 [6] ]; dataset.forEach{pattern,input,output}=> console.log |输入:,input.join, |控件:,output.join, |回答:,FindPatternPatternPattern,input.join,
如果有人想看到一个示例,而不使用不使用“向前看”或“向后看i+1”或“i-2”等的库

我认为它的工作原理与Ramda方法类似,但我选择在同一个循环中结合分区和相等性检查:

减少每一步 取阵列中与阵列长度匹配的部分 检查它是否与图案相同 如果是,则将节中最后一个元素的索引添加到reduce的结果中 代码,其中模式和数据都是字符串数组:

const findPattern = (pattern, data) => data.reduce(
  (results, _, i, all) => 
    // Check if a slice from this index equals the pattern
    arrEqual(all.slice(i, i + pattern.length), pattern)
      // Add the last index of the pattern to our results
      ? (results.push(i + pattern.length - 1), results)
      // or, return what we had
      : results, 
    []);

// Utility method to check array equality
const arrEqual = (arr1, arr2) =>
  arr1.length === arr2.length &&
  arr1.every((x, i) => x === arr2[i]);
我在几个数据集上进行了测试,认为它满足所有要求:

const findPattern=模式,data=>data.reduce 结果,i,all=> arrEqualall.slicei,i+pattern.length,pattern ? pushresults,i+模式长度-1 :结果, []; 常数arrqual=arr1,arr2=> arr1.length==arr2.length&& arr1.everyx,i=>x==arr2[i]; 常量push=xs,x=>xs.pushx,xs; //对于字符串模式,我们还可以执行以下操作: //常量arrqual=arr1,arr2=>arr1.join==arr2.join; //测试用例 常量数据集=[ //我标记了一个匹配的索引 //[i]标记应返回的最后一个匹配索引 //|标志着一个新的开始 {模式:[i,t,t],输入:['i','t','t','i','i','t','t','t','t'],输出:[2,6]}, // |0 1 [2]| 3 -4 5 [6]| 7 {pattern:[i,t],输入:['i','t','i','t','t','i','t','t','t','t','t'],输出:[1,3,7]}, // |0 [1]|2 [3]| 4 | 5 |6 [7]| 8 | 9 {pattern:[i,t,t],输入:['i','t','i','t','t','i','i','t','t','t','t'],输出:[4,8]}, // |0 1|2 3 [4]| 5 |6 7 [8]| 9 {模式:[i,t,i],输入:['i','t','i','t','i','t','i','t','i','t','i','t'],输出:[2,4,6,8]] // |0 1 [2]| |6 7 [8]| 9 // |2 3 [4] // |4 5 [6] ]; dataset.forEach{pattern,input,output}=> console.log |输入:,input.join, |控件:,output.join, |回答:,FindPatternPatternPattern,input.join,
两年后,lost traveler偶然发现了这个问题,并注意到对于具有更大输入数组或多个输入数组的可变大小特别大的图案,经典将是最好的选择

我认为这个算法值得研究

我们将从简单的命令式实现开始。然后切换到至少对我来说更直观,但可能稍微不太优化,而且绝对不太优化的内存版本与有限自动机。最后,我们将看到一些功能性的东西,但它不是100%纯的。我没有心情用JS中KMP的纯功能实现来折磨自己

前缀函数KMP,命令式实现:

函数getPatternPosarray,pattern{ 常量结果=[]; //试图解释这是浪费时间: 函数createPrefixpattern{ //用零初始化数组 常量前缀=Array.applynull,Arraypattern.length.MapNumber r、 prototype.valueOf,0; 设s=0; 前缀[0]=0; 对于let i=1;i0&&pattern[s]!==pattern[i]{ s=前缀[s-1]; } 如果模式[i]==模式[s]{ ++s; } 前缀[i]=s; } 返回前缀; } 常量前缀=createPrefixpattern; 设s=0; 对于let i=0;i<数组长度++我{ 而s>0&&pattern[s]!==数组[i]{ s=前缀[s-1]; } 如果数组[i]==pattern[s]{ ++s; } 如果s===pattern.length{ 结果:普希; s=0; } } 返回结果; } loggetPatternPos['i','t','t','i','i','t','t','t'],['i','t','t']; // [2, 6] loggetPatternPos['i','t','i','t','t','i','i','t','t','t','t'],['i','t','t']; // [4, 8] console.loggetPatternPos['a','b','a','b','b','b','c','d'],['a','b','c']; // [7] console.loggetpatterns posabaxababcxxababc.split,ababc.split; // [11, 18] console.loggetpatternPosababacx.split,ababc.split;
.作为控制台包装器{max height:100%!important;top:0;}两年后,lost traveler偶然发现了这个问题,并注意到对于具有更大输入数组或多个输入数组的可变大小和特别大的模式,经典将是非常好的

我认为这个算法值得研究

我们将从简单的命令式实现开始。然后切换到至少对我来说更直观,但可能稍微不太优化,而且绝对不太优化的内存版本与有限自动机。最后,我们将看到一些功能性的东西,但它不是100%纯的。我没有心情用JS中KMP的纯功能实现来折磨自己

前缀函数KMP,命令式实现:

函数getPatternPosarray,pattern{ 常量结果=[]; //试图解释这是浪费时间: 函数createPrefixpattern{ //用零初始化数组 const prefix=Array.applynull,Arraypattern.length.mapNumber.prototype.valueOf,0; 设s=0; 前缀[0]=0; 对于let i=1;i0&&pattern[s]!==pattern[i]{ s=前缀[s-1]; } 如果模式[i]==模式[s]{ ++s; } 前缀[i]=s; } 返回前缀; } 常量前缀=createPrefixpattern; 设s=0; 对于let i=0;i0&&pattern[s]!==数组[i]{ s=前缀[s-1]; } 如果数组[i]==pattern[s]{ ++s; } 如果s===pattern.length{ 结果:普希; s=0; } } 返回结果; } loggetPatternPos['i','t','t','i','i','t','t','t'],['i','t','t']; // [2, 6] loggetPatternPos['i','t','i','t','t','i','i','t','t','t','t'],['i','t','t']; // [4, 8] console.loggetPatternPos['a','b','a','b','b','b','c','d'],['a','b','c']; // [7] console.loggetpatterns posabaxababcxxababc.split,ababc.split; // [11, 18] console.loggetpatternPosababacx.split,ababc.split;
.as console wrapper{max height:100%!important;top:0;}这将检索i之后的每个t,而不是i和a t之后的每个t。这将起作用,但我希望找到一种不需要使用索引的解决方案。如果数组中的第一个元素是“t”,则索引为0,并且数据[index-1]将越界。Javascript对此没有问题,但它是不正确的。@ScottChristopher的解决方案除了报告结果之外,完全避免索引。这看起来很接近,除非真正的问题涉及到比字母列表更重要的东西。这将检索i之后的每个t,而不是i和a之后的每个t。这会起作用,但我希望找到一个不需要使用索引的解决方案。如果数组中的第一个元素是“t”,则索引为0,并且数据[index-1]将越界。Javascript对此没有问题,但它是不正确的。@ScottChristopher的解决方案除了报告结果之外,完全避免索引。除非真正的问题涉及到比一系列信件更为实质性的东西,否则这似乎是你能得到的最接近的结果。谢谢。创造性的解决方案,但我不喜欢全局变量的使用,比如result。@donnut,你应该使用一个函数。这个序列不起作用:getPatternPos['I','t','I','t','t','I','t','t'],['I','t','t']。@donnut,它按预期工作,什么不适用于这个模式搜索?@Arrow,如果找到完整的所需序列,它将从临时数组r中删除起始索引。检查的第一部分是比较负数,第二部分是检查最后一项。谢谢。创造性的解决方案,但我不喜欢全局变量的使用,比如result。@donnut,你应该使用一个函数。这个序列不起作用:getPatternPos['I','t','I','t','t','I','t','t'],['I','t','t']。@donnut,它按预期工作,什么不适用于这个模式搜索?@Arrow,it
如果找到完整的所需序列,则从临时数组r中移除起始索引。检查的第一部分是比较负数,第二部分是检查最后一项。问题:尝试在“i”和“t”之后检索“t”:谢谢,但不是功能解决方案,它存在数据中负索引的问题,例如数据[0-2]负索引返回未定义,以及条件是否有效。数据[-2]等于未定义。刚/紧接之后和之后之间存在差异。对于后者,您的解决方案是正确的@Donut,如果您可以将问题更新为所需的正确内容,那就太好了。问题:尝试在“i”和“t”之后检索“t”:谢谢,但不是函数解决方案,它存在数据中负索引的问题,例如数据[0-2]负索引返回未定义,以及条件是否有效。数据[-2]等于未定义。刚/紧接之后和之后之间存在差异。对于后者,您的解决方案是正确的@donnut,如果你能将你的问题更新到所需的正确内容,那就太好了。非常优雅的解决方案!如果我们能避免负面因素就好了。我知道,它可以在javascript中工作,但仍然是的,这也可以工作,尽管您可以将返回语句更改为memo[2]+memo[1]+c==='itt',因为备忘录列表是颠倒的。非常优雅的解决方案!如果我们能避免负面因素就好了。我知道,它可以在javascript中工作,但是仍然是的,这也可以工作,尽管您可以将return语句更改为memo[2]+memo[1]+c==='itt',因为memo列表是颠倒的。