【问题标题】:javascript, diff function returning same stringjavascript,diff函数返回相同的字符串
【发布时间】:2011-05-15 23:30:45
【问题描述】:

我想知道是否有人可以帮助我解决我的差异功能。它应该找到2个输入之间的差异。该函数接受 2 个数组,因此如果数组 1 有..“word1”、“word2”并且数组 2 有“word1”、“word2”和“word3”,它应该只返回“word3”。它在大多数情况下都可以工作,但是使用下面的某些输入,它就不起作用了。

function diff(a1, a2) {

if (a1.length > a2.length
       || a1.length == a2.length) {
    return [""];
}
a1 = a1.slice(0);
a2 = a2.slice(0);


for (i = 0; i < a1.length; i++) {
    for (k = 0; k < a2.length; k++) {
        if (a1[i] == a2[k]) {
            a1.splice(i, 1);
            a2.splice(k, 1);
        }
    }
}

for (j = 0; j < a2.length; j++) {
    for (p = 0; p < a1.length; p++) {
        if (a2[j] == a1[p]) {
            a2.splice(p, 1);
            a1.splice(j, 1);
        }
    }
}


a1 = a1.concat(a2);
return a1;
}

var s1 = ["one", "two", "three", "four",];
var s2 = ["one", "two", "three", "four", "five"];


document.write(diff(s1, s2));

答案应该只返回“五”,但它返回“四”、“四”、“五”。帮助将不胜感激。我超级卡住了。非常感谢!

【问题讨论】:

  • 你能详细说明你的算法应该做什么吗?你的两个例子涵盖的范围很小。
  • 您通过在循环变量之前省略 var 在您的 diff 函数中创建大量全局变量,希望您不要在生产代码中这样做。

标签: javascript arrays string diff


【解决方案1】:

据我了解,您希望返回一个仅包含两者不同元素的数组。试试这种方式,没有复杂的双循环和拼接等等:

function diff(a1, a2) {

  var aa1 = {}, aa2 = {}, res = [];

  // create an object from a1, containing value:array-index pairs:
  for (var i = 0; i < a1.length; i++) {
      aa1[a1[i]] = i;
  }
  // create an object from a2 like the one from a1
  for (var i = 0; i < a2.length; i++) {
      aa2[a2[i]] = i;
  }
  /**
    * loop through the first object (from a1)
    * if a value in this object is not found in 
    * the object from a2, push that value to 
    * the result array (res)
   */
  for (var l in aa1){
    if (aa1.hasOwnProperty(l) && !(l in aa2)) {
        res.push(a1[aa1[l]]);
    }
  }
  /**
    * but the second array can also contain
    * values differing from the values in the first.
    * So, repeat the above for the object created 
    * from a2
   */
  for (var l in aa2){
   if (aa2.hasOwnProperty(l) && !(l in aa1)) {
        res.push(a2[aa2[l]]);
   }
 }
 /**
   * now res contains all different values
   * note: double values are not counted
   * so ['one','two','tree'] vs ['one','two','four','four']
   * will return ['tree','four']
   * note2: if you want to find the first difference,
   * return res[0]
   */

 return res;
}

如果它只是您想要找到的第一个差异,这个(仅限数组)方法可以:

function diff(a1, a2) {
  var firstdiff = null, i = -1;

  /**
    * local function to check if value [val] 
    * exists in array [arr]. Called from
    * within the loops
    */
  function check(val,arr){
      var i = -1;
      while(++i<arr.length){
          if(val === arr[i]){ return true;}
      }
      return false;
  }
  // loop a1 and check values vs a2-values
  while (++i<a1.length){
    if (!check(a1[i],a2)) {
      return firstdiff = a1[i];
    }
  }
  // no difference found, continue a2 vs a1
  i = -1;
  while (++i<a2.length){
    if (!check(a2[i],a1)) {
      return firstdiff = a2[i];;
    }
  }
  // there are no differences, firstdiff = null
  return firstdiff;
}

【讨论】:

  • 哇哦,你上面的代码真的很好用!你介意给我解释一下吗?我有点难以理解。非常感谢! = )
【解决方案2】:

问题在于 array.splice 减少了数组的长度,从而使 for 循环跳过了元素。可能的解决方案是减少迭代器。

编辑:

当您拼接数组时,它会从数组中删除元素,使其更短。所以让我们假设我们正在运行这段代码:

test_array = [1, 2, 3, 4, 5];
for(i = 0; i < test_array.length; i++) {
    document.write(test_array[i]);
    if(i == 2) {
        test_array.splice(i, 1);
    }
}

你可以看到它输出的是 1235,而不是 12345。那是因为当 i = 2 并且元素被删除时,数组中的所有元素都重新计算了它们的索引。所以如果在拼接之前数组是:

  • [0] = 1
  • [1] = 2
  • [2] = 3
  • [3] = 4
  • [4] = 5

之后变成:

  • [0] = 1
  • [1] = 2
  • [2] = 4
  • [3] = 5

同时,for 循环移动到 i = 3,但 test_array[3] 不是 4,而是现在 5,因此跳过了数字 4。

一个简单的解决方案是您可以减少迭代器。

例子:

test_array = [1, 2, 3, 4, 5];
for(i = 0; i < test_array.length; i++) {
    document.write(test_array[i]);
    if(i == 2) {
        test_array.splice(i, 1);
        i--;
    }
}

【讨论】:

  • 哦,我不太清楚你的意思。你不希望数组在元素被删除后缩小吗?如果元素被删除,它会跳过什么?你不想让它进入下一个元素吗?谢谢!
  • 我在手机上做了我原来的答案,我现在已经详细说明了。
  • 太酷了。非常感谢!这有助于为什么 splice 跳过索引。我仍然不确定数组的副本是如何工作的。那也不会跳过索引吗?即使您正在拼接原始副本,如果 i 递增到下一个索引,并且在副本数组中恰好有另一个副本,它将删除向下移动元素旁边的元素(我相信您想删除移动元素)
  • AAAAH,你说得对,复制数组在这种情况下不起作用,我完全搞砸了,哈哈,很好。但是,是的,如果拼接不止一次,最终会删除原始数组中的错误元素。
  • @Crystal,第一个双循环:在 i=0 k=0 "one"=="one" 所以每个都被删除;在 i=0 k=1 "二"!="三";在 i=0 k=2 “二”!=“四”;在 0 3 "二"!="五"; 1 0 “三”!=“二”; 1 1 "three"=="three" 所以每个都被删除; 1 2 “四”!=“五”;没有更多的循环。在第二个双循环中: 0 0 "two"=="two" 所以每个都被删除; 0 1 没有运行,因为此时 a1 只有“四个”,所以 a1.length==1。因此,我们将 a1 中的“四”与 a2 中的“四”和“五”连接起来。
【解决方案3】:

这条评论很快解释了你的代码在做什么:

@Crystal, first double loop: at i=0 k=0 "one"=="one" so each is removed; at i=0 k=1 "two"!="three"; at i=0 k=2 "two"!="four"; at 0 3 "two"!="five"; 1 0 "three"!="two"; 1 1 "three"=="three" so each is removed; 1 2 "four"!="five"; no more cycles. In the second double loop: 0 0 "two"=="two" so each is removed; 0 1 is not run because at this point a1 only has "four" so a1.length==1. Thus we concat "four" in a1 with "four" and "five" in a2

要得到你想要的答案,改变

a1.splice(i, 1);

a1.splice(i--, 1);

然后冲洗,重复双循环中的其他 3 个类似情况。因此,您将有 4 种情况,采用拼接并递减第一个参数。这种递减弥补了接头的移除。

但是,您现在只需要其中一个双循环,因为这将消除所有重叠。

另外,为什么要在顶部进行检查以过滤掉 a1 长度大于或等于 a2 长度的情况?也删除该部分。

答案是“五”。如果需要,您可以测试非常不同的数据,它应该可以工作。

所以这可能是你的程序:

function diff(a1, a2) {

a1 = a1.slice(0);
a2 = a2.slice(0);


for (i = 0; i < a1.length; i++) {
    for (k = 0; k < a2.length; k++) {
        if (a1[i] == a2[k]) {
            a1.splice(i--, 1);
            a2.splice(k--, 1);
        }
    }
}


a1 = a1.concat(a2);
return a1;
}

var s1 = ["one", "two", "seven", "three", "four",];
var s2 = ["one", "two", "four", "five", "six"];


document.write(diff(s1, s2));

【讨论】:

    【解决方案4】:

    你在拼接的时候遍历了数组,但是你没有用你的索引来调整它。

    【讨论】:

      猜你喜欢
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      • 2011-04-14
      • 1970-01-01
      • 2015-07-31
      • 2017-05-12
      • 2015-02-10
      • 2016-12-18
      相关资源
      最近更新 更多