【问题标题】:Filter n arrays by excluding values that don't exist in each通过排除每个数组中不存在的值来过滤 n 个数组
【发布时间】:2011-01-25 17:44:41
【问题描述】:

我有 n 个数组,我需要确定 x 是否在所有 n 个数组中。 (其中 n 是任意数字,而 x 是数值)我有类似以下的内容,但它总是以 false 结尾。

function filterArrays()
{
  var x = $(this).attr('id'); // ex: 2
  var arrays = [[1,2,3],[2,4,6]];
  var result = false;
  for each (var n in arrays)
  {
    result = result ^ (n.indexOf(x) > -1);
  }
}

x 在两个数组中时,我如何使result 等于true,但当x 不在两个数组中时,使result 等于false

上面的函数将与 jQuery 的 filter() 方法一起使用。示例:

$(arrayOfElementsWithNumericIds).filter(arrayFilter);
// arrayOfElementsWithNumericIds prototype: [div#1,div#2,div#3,...]

我认为需要按位运算,但我可能错了。请解释为什么您的解决方案是正确的以及为什么我的解决方案不起作用。 (积分)

【问题讨论】:

    标签: javascript jquery arrays


    【解决方案1】:

    以下是您的示例的一些问题:

    • 比较数字和字符串(id 是一个字符串)。使用x = parseInt(...)
    • 使用^ 运算符。而是将result 初始化为true 并使用&&
    • 摆脱each。正确的语法是for (key in object)

    我已经尽可能少地修改了你的代码:

    function filterArrays()
    {
        var x = parseInt($(this).attr('id')); // ex: 2
        var arrays = [[1,2,3],[2,4,6]];
        var result = true;
        for (var n in arrays)
        {
            result = result && (arrays[n].indexOf(x) > -1);
        }
        return result;
    }
    

    话虽如此,您可以使用Array.every()Array.some() 真正优化您的代码。此外,使用 $(this).attr('id') 会不必要地创建一个 jQuery 对象,因为您可以直接说 this.id

    function filterArrays()
    {
        var x = parseInt(this.id); // ex: 2
        var arrays = [[1,2,3],[2,4,6]];
        var result = arrays.every(function(array)
        {
            return array.some(function(item)
            {
                return item === x;
            });
        });
        return result;
    }
    

    【讨论】:

    • 感谢您对如何改进代码提出建议。虽然我不同意您对我示例中的错误使用量词“很多”,但我感谢您指出您发现的“少数”并解释如何/为什么可以改进它们。您的回答是最彻底的,因此是我会接受的。感谢您的努力。
    • @sholsinger:谢谢。我所说的“很多”并不是什么意思……你是对的,“很少”更准确。 :-)
    • 我的实际设置不同。在我的真实代码中,arrays 是一个对象,因此不支持every()。有没有一种方法可以将对象转换为数组而不会产生太多开销?
    • @sholsinger:你可以,但它不会给你带来太多好处,如果有的话。对于迭代一个对象,使用你已经拥有的for ... in 应该足够好。如果result 为假,我唯一要添加的是循环中的break 语句。
    【解决方案2】:

    我认为您正在寻找这个:

      var result = true;
     for each (var n in arrays)
      {
        result = result && (n.indexOf(x) > -1);
      }
    

    即假设该值是在所有数组中开始的。然后使用 AND (&&) 运算符得到

      true AND (value is in current array)
    

    如果在任何时候该值不在数组中,它就会变为假,整个操作将是假的。否则在循环结束之前它保持为真。

    【讨论】:

    • 谢谢您可能已经知道,但您的回答是正确的,并且会修复我提供的示例代码。感谢您花时间制定答案。
    【解决方案3】:

    异或不是要走的路。这样看:

    search for 2, start  result = false
    1st array: 2 is present, result = false xor true = true
    2nd array: 2 is present, result = true xor true = false
    end: result is false (WRONG)
    
    search for 4, start result = false
    1st array: 4 is present, result = false xor true = true
    2nd array: 4 is  absent, result = true xor false = true
    end: result is true (WRONG)
    

    你想要一个累积的位和。

    start: result = true, search for 2
    1st array: 2 is present, result = true and true = true
    2nd array: 2 is present, result = true and true = true
    end: result is true (RIGHT)
    
    start: result = true, search for 4
    1st array: 4 is present, result = true and true = true
    2nd array: 4 is absent, result = true and false = false
    end: result if false (RIGHT)
    

    【讨论】:

    • 感谢您关于将 XOR 更改为 AND 的建议。这在技术上是正确的,并且可以解决问题。 (主要是)感谢您的努力。
    【解决方案4】:

    为什么不用 contains 方法扩展数组原型?这样你就可以循环遍历每个数组和或/和当前结果与前一个数组。

    【讨论】:

      【解决方案5】:

      如果你愿意,你可以遍历你的“数组”对象,但是,我认为你只需要一个 Set Intersect 操作。这是在 jQuery 中执行此操作的一种方法,它不会关心 x 的 attr(id) 值是整数还是字符串。我正在吃午饭,我会在一个页面中快速测试一下...

      function filterArrays(){
        var x = $(this).attr("id");
        var arrays = [[1,2,3],[2,4,6]];
        var result = ($.inArray(arrays[0], x )>0 && $.inArray(arrays[1], x) >0);
        return result;
      }
      

      【讨论】:

      • @marc b 我同意,逐位累积和运算。我的帖子是一个 n^2 解决方案 afaik。
      • 在我对预先编写的代码的回答中查看两种不同的 Set 实现。
      【解决方案6】:

      使用http://phrogz.net/JS/ArraySetMath.js 你可以:

      var sets  = [[1,2,3],[2,3,7],[1,7,2]];
      var isect = sets[0];
      for (var i=1,len=sets.length;i<len;++i){
        isect = isect.intersection( sets[i] );
      }
      console.log( isect );
      // [2]
      

      或者,使用JS.Set 你可以:

      var sets  = [[1,2,3],[2,3,7],[1,7,2]];
      
      // Or JS.HashSet or JS.Set
      var isect = new JS.SortedSet(sets[0]);
      for (var i=1,len=sets.length;i<len;++i){
        isect = isect.intersection( new JS.SortedSet(sets[i]) );
      }
      

      【讨论】:

      • 谢谢,感谢您为制作该库所做的努力。也就是说,我现在不想给我的脚本增加任何额外的开销。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-29
      • 2021-11-16
      • 2017-11-03
      • 2021-05-31
      • 1970-01-01
      相关资源
      最近更新 更多