【问题标题】:Compare two binary vector比较两个二进制向量
【发布时间】:2016-06-29 08:35:05
【问题描述】:

我有两个位数组,每个长度为 200.000。我需要以相同的顺序在每个列表中找到多少个 1。让我画出来:

1   0
**1 1**
0   0
0   1
0   0
**1 1**
1   0
0   1
..  ..

所以结果应该是 2。

我在 -two 中进行了这个比较,嵌套了大约 2000 万次 :)。

我现在使用带有 & 运算符的位数组而不是使用 popCount 方法来查找结果。

那么你对这类问题有什么建议。你会在哪里存储这些向量,你会如何以我想要的方式比较它们?我需要速度。

更新: 我已经用 760 个长度的阵列完成了这项工作,我的方法用了不到 5 秒的时间。 cmets中建议的每种方法都花费了> 1分钟(我停止了程序) 所以我想是我必须回答它。我简化了我的代码。

      for(i<761)
   var vector1 = matris[getvectorthing];
          for(j=i+1<761)
        {
   var vector2 = matris[getvectorthing];
            var similarityResult = vector1Temp.And(vector2);
            var similarityValuePay = popCount(similarityResult);
    //similarityValuePay  is result that i want
        }
    }

         private static int popCount(BitArray simRes)
            {
                Int32[] ints = new Int32[(simRes.Count >> 5) + 1];
                simRes.CopyTo(ints, 0);
                Int32 count = 0;
                // fix for not truncated bits in last integer that may have been set to true with SetAll()
                ints[ints.Length - 1] &= ~(-1 << (simRes.Count % 32));

                var tempInt = ints.Where(k => k != 0).ToArray();

                for (Int32 i = 0; i < tempInt.Length; i++)
                {
                    Int32 c = tempInt[i];
                    // magic (http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel)
                    unchecked
                    {
                        c = c - ((c >> 1) & 0x55555555);
                        c = (c & 0x33333333) + ((c >> 2) & 0x33333333);
                        c = ((c + (c >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
                    }
                    count += c;
                }
                return count;
            }

我问它是因为可能有很多切割方法或简单的调整来提高性能。例如:

var tempInt = ints.Where(k => k != 0).ToArray();

这个 ToArray() 似乎是我需要修复的部分。等等

【问题讨论】:

  • 写一些代码给我们看看。
  • " -two nested for- " - 你为什么需要它?

标签: c# arrays vector bitarray


【解决方案1】:

您可以使用And() 方法解决此问题

BitArray ba = new BitArray(new bool[] { true, true, false, false, false, true, true, false });
BitArray ba2 = new BitArray(new bool[] { false, true, false, true, false, true, false, true });

int result = ba.And(ba2).Cast<bool>().Count(x => x); //2

【讨论】:

    【解决方案2】:

    假设ab 等于Length

    int[] a = new[] {1,0,1, ...};
    int[] b = new[] {0,0,1, ...};
    int c = 0;
    for (int i = 0; i < a.Length; i++)
        c += a[i] == 1 && b[i] == 1 ? 1 : 0;
    

    简单。时间复杂度为 O(n),其中 n 是数组中的元素数。

    【讨论】:

      【解决方案3】:

      更简洁的答案:

              bool[] A = ...;
              bool[] B = ...;
      
      
              var result = A.Where((val, ix)=>val && B[ix]).Count();
      

      【讨论】:

      • 与 And 运算符相比,它是一种无效的方式。你能再看看我的更新吗?我试过这个 btw 比我停止它的方法花费了 10 倍的秒
      【解决方案4】:

      使用And 方法,并计数true,我认为这比其他答案更快。

      var bit1 = new BitArray(new bool[]{true, false, ...});
      var bit2 = new BitArray(new bool[]{false, false, ...});
      var and = bit1.And(bit2);
      
      var result = 0; //Total count I think you want.
      for (int i = 0; i < and.Length; i++)
      {
          if (and[i])
          {
              result++;
          }
      }
      

      更新

      我想出了一个提高性能的解决方案。

      popCount 替换为:

      private static int popCount(BitArray simRes)
      {
          Int32[] ints = new Int32[(simRes.Count >> 5) + 1];
          simRes.CopyTo(ints, 0);
          Int32 count = 0;
          // fix for not truncated bits in last integer that may have been set to true with SetAll()
          ints[ints.Length - 1] &= ~(-1 << (simRes.Count % 32));
      
          for (Int32 i = 0; i < ints.Length; i++)
          {
              Int32 c = ints[i];
              if (c == 0)
              {
                  continue;
              }
              // magic (http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel)
              unchecked
              {
                  c = c - ((c >> 1) & 0x55555555);
                  c = (c & 0x33333333) + ((c >> 2) & 0x33333333);
                  c = ((c + (c >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
              }
              count += c;
          }
          return count;
      }
      

      在我的机器中,当simRes.Length &gt; 16000000if(c == 0){...} 块提供良好的性能。但是当simRes.Length &lt; 16000000if(c == 0){...}块应该被删除。

      【讨论】:

      • 我已经有了很大的循环,这是我想到的第一件事。你能再看看我的更新吗?
      • 哦.. 你的 popCount 比我的回答快很多
      • 我看到你删除了行 var tempInt = ints.Where(k => k != 0).ToArray();我今天已经做到了:) 无论如何谢谢
      • 我很欣赏@deyu 的工作,但实际上这是我的解决方案。但是 nvm 我将其标记为已接受只是为了再次说明这是迄今为止我们得到的最佳答案。
      【解决方案5】:
      static void Main()
      {
              var a = new BitArray(new bool[]{true, false,true});
              var b = new BitArray(new bool[]{false, false,true});
              int result = 0;
              int size = Math.Min( a.Length, b.Length); //or a.Length or 200000
              for (int i = 0; i < size ; i++)
              {
                 if (a[i] == true && b[i] == true )
                 {
                    result++;
                 }
              }
              Console.WriteLine("{0}",result);
      }
      

      【讨论】:

      • WTF?为什么我和其他一些答案要投反对票?复杂度是 O(n) 并且肯定不会超过在 O(n) 迭代旁边进行 AND 操作!
      • 因为我在问题中所说的确实比建议的方法要好得多,而且它们是人们首先想到的第一件事
      • @KemalCanKara 你在我回答后更新了你的问题!此外,您不知道在数组之间进行 AND 并最终计算 1 并不比我和其他人建议您做的更有效
      猜你喜欢
      • 1970-01-01
      • 2011-06-14
      • 1970-01-01
      • 1970-01-01
      • 2010-12-25
      • 2017-07-26
      • 2015-05-20
      • 1970-01-01
      • 2012-11-01
      相关资源
      最近更新 更多