代码之家  ›  专栏  ›  技术社区  ›  mpen

减去散列集(并返回副本)?

  •  14
  • mpen  · 技术社区  · 14 年前

    我有一个散列集,

    var universe = new HashSet<int>();
    

    var sets = new List<HashSet<int>>(numSets);
    

    我想减去一大块,我可以这样做:

    var remaining = universe.ExceptWith(sets[0]);
    

    ExceptWith 工作到位。我不想修改 universe . 我应该先克隆它,还是有更好的方法?

    6 回复  |  直到 9 年前
        1
  •  15
  •   Thomas Levesque    14 年前

    我想我应该克隆它 第一?我该怎么做?

    var universe = new HashSet<int>();
    var subset = new HashSet<int>();
    ...
    
    // clone the universe
    var remaining = new HashSet<int>(universe);
    remaining.ExceptWith(subset);
    

    Except 扩展方法,但可能更快(您应该运行一些性能测试以确保)

        2
  •  11
  •   James McNellis    14 年前

    怎么样 Except() ?

    var x = new HashSet<int>();
    var y = new HashSet<int>();
    
    var xminusy = new HashSet<int>(x.Except(y));
    
        3
  •  8
  •   mpen    10 年前

    Except 方法防止克隆和使用哈希集本机函数 ExceptWith . 结果如下。

    static class Program
    {
        public static HashSet<T> ToSet<T>(this IEnumerable<T> collection)
        {
            return new HashSet<T>(collection);
        }
    
        public static HashSet<T> Subtract<T>(this HashSet<T> set, IEnumerable<T> other)
        {
            var clone = set.ToSet();
            clone.ExceptWith(other);
            return clone;
        }
    
        static void Main(string[] args)
        {
            var A = new HashSet<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            var B = new HashSet<int> { 2, 4, 6, 8, 10 };
            var sw = new Stopwatch();
    
            sw.Restart();
            for (int i = 0; i < 1000000; ++i)
            {
                var C = A.Except(B).ToSet();
            }
            sw.Stop();
            Console.WriteLine("Linq: {0} ms", sw.ElapsedMilliseconds);
    
            sw.Restart();
            for (int i = 0; i < 1000000; ++i)
            {
                var C = A.Subtract(B);
            }
            sw.Stop();
            Console.WriteLine("Native: {0} ms", sw.ElapsedMilliseconds);
    
            Console.ReadLine();
        }
    }
    


    本机:762 ms

    http://programanddesign.com/cs/subtracting-sets/

        4
  •  1
  •   verisimilidude    14 年前

        5
  •  0
  •   kitta    6 年前

    回答得很晚,但有时可能有用。

    @mpen用Linq的Except(IEnumerable<>)回答

    这使得linq循环通过IEnumerable检查它是否包含。

    setA.Where(i=>!挫折包含(i)

        6
  •  0
  •   PJJ    6 年前

    // no more set ops planned? then returning list is an option
    public static List<T> ExceptWith<T>(HashSet<T> allObjects, Hashset<T> minus)
    {
        //  Set Capacity of list   (allObjects.Count-minus.Count?)
        List<T> retlst = new List<T>(allObjects.Count); 
    
        foreach( var obj in allObjects) {
            if( minus.Contains(obj)==false)
                retlst.Add(obj);
        }
        return retlst;
    }
    
    // Special case where quantity of copying will be high
    // more expensive in fact than just adding
    public static HashSet<T> ExceptWith<T>(HashSet<T> allObjects, HashSet<T> minus)
    {
        if( minus.Count > allObjects.Count * 7/8 )
        {
            HashSet<T> retHash = new HashSet<T>(); 
    
            foreach( var obj in allObjects) {
                if( minus.Contains(obj)==false)
                    retHash.Add(obj);
            }
            return retHash;
    
        }
        else
        {
            // usual clone and remove
        }
    }