在C#中计算大字符串数组的功率集

时间:2016-03-31 12:17:02

标签: c# out-of-memory

我想计算字符串数组的幂集(将其视为一组)。当我超过26个元素时,它会出现内存异常。

List<int> ff = new List<int>();
double length = Math.Pow(2, 29);
for (int i = 0; i < length; i++)
{
   ff.Add(1);
}

如果你运行它,上面的代码将产生该异常。集合的大小可能会达到1000.因此该集合的功率集大小将为2 ^ 1000。

我该如何处理?

修改

我知道上面的代码不是电源设置的功能。我只是在检查c#能够容纳多大的数组。

 private static Dictionary<int, object> PowerSetB(string[] input)
        {
            int n = input.Length;
            // Power set contains 2^N subsets.
            int powerSetCount = 1 << n;
            var ans = new Dictionary<int, object>();

            for (int setMask = 0; setMask < powerSetCount; setMask++)
            {
                var s = new ArrayList();
                for (int i = 0; i < n; i++)
                {
                    // Checking whether i'th element of input collection should go to the current subset.
                    if ((setMask & (1 << i)) > 0)
                        s.Add(input[i]);
                }
                ans[setMask] = s;
            }
            return ans;
        }

以上代码是我的电源设置功能。<​​/ p>

提前谢谢。

1 个答案:

答案 0 :(得分:4)

你真的想将所有项目存储在内存中吗?我建议使用IEnumerable<int>代替具体化 List<int>

// just enumeration, coefficients aren't stored
public static IEnumerable<int> Serie(Func<int, int> coefByIndex) {
  if (null == coefByIndex)
    throw new ArgumentNullException("coefByIndex");

  for (int i = 0; ; ++i)
    yield return coefByIndex(i);
}

// Let's sum up all 2**29 values, 
// i.e. compute f(1) summing up 2**29 items (it's a long process...)
// sum = 1.44115187606094E+17 (diverges, as we might have expected)
Double sum = Serie(index => index)
  .Select(x => x * 1.0)
  .Take(1 << 29)
  .Sum();

修改:一旦agian,请不要实现Dictionary<int, object>)巨大的结果!提供IReadOnlyDictionary<int, int[]> 界面,但不实施为Dictionary<int, object>
像这样:

  // ArrayList is an obsolete collection;
  // int[] far more natural here
  public sealed class PowerSet: IReadOnlyDictionary<int, int[]> {
    private int m_Power;

    private int[] getItem(int index) {
      int[] result = new int[m_Power];

      for (int i = 0; i < m_Power; ++i) {
        result[i] = index % 2;

        index /= 2;
      }

      return result;
    }

    public PowerSet(int power) {
      m_Power = power;
    }

    public int[] this[int key] {
      get {
        if (key >= 0 && key < Count)
          return getItem(key);
        else
          throw new ArgumentOutOfRangeException("key");
      }
    }

    public int Count {
      get {
        return 1 << m_Power;
      }
    }

    public IEnumerable<int> Keys {
      get {
        return Enumerable.Range(0, Count);
      }
    }

    public IEnumerable<int[]> Values {
      get {
        return Enumerable.Range(0, Count).Select(index => getItem(index));
      }
    }

    public bool ContainsKey(int key) {
      return key >= 0 && key < Count;
    }

    public IEnumerator<KeyValuePair<int, int[]>> GetEnumerator() {
      return Enumerable
        .Range(0, Count)
        .Select(index => new KeyValuePair<int, int[]>(index, getItem(index)))
        .GetEnumerator();
    }

    public bool TryGetValue(int key, out int[] value) {
      if (key >= 0 && key < Count) {
        value = getItem(key);

        return true;
      }

      value = null;
      return false;
    }

    IEnumerator IEnumerable.GetEnumerator() {
      return this.GetEnumerator();
    }
  }

  ... 

  // Just an easy call
  private static IDictionary<int, int[]> PowerSetB(string[] input) {
    return new PowerSet(input.Length);
  }