【问题标题】:What is the equivalent of LinkedHashSet (Java) in C#?C# 中的 LinkedHashSet (Java) 等价物是什么?
【发布时间】:2012-02-19 03:52:13
【问题描述】:

什么是 C# 中的 LinkedHashSet (Java) 的等价物?

【问题讨论】:

  • 如果你描述一下LinkedHashSet的作用就好了:)
  • 这是一个维护插入顺序的集合。它使用一个后备链表来做到这一点。

标签: java c# set


【解决方案1】:

HashSet 可以完成这项工作,因为它实际上等同于 Java 中的 LinkedHashSet。 HashSet 由链表支持 - 尽管文档没有明确声明它保留顺序或它由基于数组的链表支持。从the source code可以看出,实现是一个LinkedHashSet。

不允许重复,就像 Java LinkedHashSet 一样。这与 LinkedHashSet 之间的一个区别是,如果您从集合中删除某些内容,它只会将元素标记为数组中的空闲元素,因此在 remove() 之后添加一个项目会在“追加”之前首先填充空数组插槽。解决这个问题的方法是调用 TrimExcess() 方法。因此,虽然在许多用例中并不完全相同,例如序列化和反序列化,对于有效的不可变集合,一旦创建它就可以很好地工作。

您始终可以继承并覆盖 remove() 以始终调用 TrimExcess() 以获得相同的行为。为了清楚起见,您可以将类命名为 LinkedHashSet!

using System;
using System.Collections.Generic;


namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            String[] crew = {"Spock", "Kirk", "Bones", "Picard", "Uhura", "Chekov"};
            HashSet<String> linkedHashSet = new HashSet<String>(crew);

            // Show order is preserved
            foreach(String value in linkedHashSet){
                Console.Write(value); Console.Write(" ");
            }

            // Remove from the middle
            linkedHashSet.Remove("Picard");
            Console.WriteLine();
            foreach(String value in linkedHashSet){
                Console.Write(value); Console.Write(" ");
            }

            // Add it back but it is back in the middle not the end
            linkedHashSet.Add("Picard");
            Console.WriteLine();
            foreach(String value in linkedHashSet){
                Console.Write(value); Console.Write(" ");
            }

            // Remove and trim then add
            linkedHashSet.Remove("Picard");
            linkedHashSet.TrimExcess();
            linkedHashSet.Add("Picard");
            Console.WriteLine();
            foreach(String value in linkedHashSet){
                Console.Write(value); Console.Write(" ");
            }
            Console.WriteLine();
        }
    }
}

输出:

Spock Kirk Bones Picard Uhura Chekov
Spock Kirk Bones Uhura Chekov
Spock Kirk Bones Picard Uhura Chekov
Spock Kirk Bones Uhura Chekov Picard

【讨论】:

    【解决方案2】:

    C# 中没有直接的等价物。要使用的适当类取决于所需的行为。 HashSet 类将保留元素的唯一性。您可能还想查看SortedSetSortedDictionary

    C# 中没有将 Linked List 与 Set 数据结构中所需的唯一性相结合的类,因此如果您需要这两种行为,则需要构建自己的行为。

    【讨论】:

      【解决方案3】:

      我完成了未完成的方法,并大致完善了'achitaka-san'发布的课程。

      public class LinkedHashSet<T> : ISet<T> {
      
          private readonly IDictionary<T, LinkedListNode<T>> dict;
          private readonly LinkedList<T> list;
      
          public LinkedHashSet(int initialCapacity) {
              this.dict = new Dictionary<T,LinkedListNode<T>>(initialCapacity);
              this.list = new LinkedList<T>();
          }
      
          public LinkedHashSet() {
              this.dict = new Dictionary<T,LinkedListNode<T>>();
              this.list = new LinkedList<T>();
          }
      
          public LinkedHashSet(IEnumerable<T> e) : this() {
              addEnumerable(e);
          }
      
          public LinkedHashSet(int initialCapacity, IEnumerable<T> e) : this(initialCapacity) {
              addEnumerable(e);
          }
      
          private void addEnumerable(IEnumerable<T> e) {
              foreach (T t in e) {
                  Add(t);
              }
          }
      
          //
          // ISet implementation
          //
      
          public bool Add(T item) {
              if (this.dict.ContainsKey(item)) {
                  return false;
              }
              LinkedListNode<T> node = this.list.AddLast(item);
              this.dict[item] = node;
              return true;
          }
      
          public void ExceptWith(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              foreach (T t in other) {
                  Remove(t);
              }
          }
      
          public void IntersectWith(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              T[] ts = new T[Count];
              CopyTo(ts, 0);
              foreach (T t in ts) {
                  if (!System.Linq.Enumerable.Contains(other, t)) {
                      Remove(t);
                  }
              }
          }
      
          public bool IsProperSubsetOf(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              int contains = 0;
              int noContains = 0;
              foreach (T t in other) {
                  if (Contains(t)) {
                      contains++;
                  } else {
                      noContains++;
                  }
              }
              return contains == Count && noContains > 0;
          }
      
          public bool IsProperSupersetOf(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              int otherCount = System.Linq.Enumerable.Count(other);
              if (Count <= otherCount) {
                  return false;
              }
              int contains = 0;
              int noContains = 0;
              foreach (T t in this) {
                  if (System.Linq.Enumerable.Contains(other, t)) {
                      contains++;
                  } else {
                      noContains++;
                  }
              }
              return contains == otherCount && noContains > 0;
          }
      
          public bool IsSubsetOf(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              foreach (T t in this) {
                  if (!System.Linq.Enumerable.Contains(other, t)) {
                      return false;
                  }
              }
              return true;
          }
      
          public bool IsSupersetOf(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              foreach (T t in other) {
                  if (!Contains(t)) {
                      return false;
                  }
              }
              return true;
          }
      
          public bool Overlaps(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              foreach (T t in other) {
                  if (Contains(t)) {
                      return true;
                  }
              }
              return false;
          }
      
          public bool SetEquals(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              int otherCount = System.Linq.Enumerable.Count(other);
              if (Count != otherCount) {
                  return false;
              }
              return IsSupersetOf(other);
          }
      
          public void SymmetricExceptWith(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              T[] ts = new T[Count];
              CopyTo(ts, 0);
              HashSet<T> otherList = new HashSet<T>(other);
              foreach (T t in ts) {
                  if (otherList.Contains(t)) {
                      Remove(t);
                      otherList.Remove(t);
                  }
              }
              foreach (T t in otherList) {
                  Add(t);
              }
          }
      
          public void UnionWith(IEnumerable<T> other) {
              if (other == null) {
                  throw new ArgumentNullException("other cannot be null");
              }
              foreach (T t in other) {
                  Add(t);
              }
          }
      
          //
          // ICollection<T> implementation
          //
      
          public int Count {
              get {
                  return this.dict.Count;
              }
          }
      
          public bool IsReadOnly {
              get {
                  return this.dict.IsReadOnly;
              }
          }
      
          void ICollection<T>.Add(T item) {
              Add(item);
          }
      
          public void Clear() {
              this.dict.Clear();
              this.list.Clear();
          }
      
          public bool Contains(T item) {
              return this.dict.ContainsKey(item);
          }
      
          public void CopyTo(T[] array, int arrayIndex) {
              this.list.CopyTo(array, arrayIndex);
          }
      
          public bool Remove(T item) {
              LinkedListNode<T> node;
              if (!this.dict.TryGetValue(item, out node)) {
                  return false;
              }
              this.dict.Remove(item);
              this.list.Remove(node);
              return true;
          }
      
          //
          // IEnumerable<T> implementation
          //
      
          public IEnumerator<T> GetEnumerator() {
              return this.list.GetEnumerator();
          }
      
          //
          // IEnumerable implementation
          //
      
          IEnumerator IEnumerable.GetEnumerator() {
              return this.list.GetEnumerator();
          }
      
      }
      

      需要的用途:

      using System;
      using System.Collections;
      using System.Collections.Generic;
      

      警告:该类大部分未经测试,尤其是 ISet 方法。使用风险自负。
      我希望有人觉得这很有用。 :)

      【讨论】:

      • 不错的实现,但是有两个单独的集合是超级慢的,它完全违背了 LinkedHashSet 的目的。一个有效的实现会使列表侵入条目。
      【解决方案4】:

      我已经简单地实现了一个HashSet,它保证了插入顺序。它使用Dictionary 查找项目并使用LinkedList 保留顺序。所有三个插入、删除和查找仍然在 O(1) 中工作。

      public class OrderedSet<T> : ISet<T>
      {
          private readonly IDictionary<T, LinkedListNode<T>> m_Dictionary;
          private readonly LinkedList<T> m_LinkedList;
      
          public OrderedSet()
          {
              m_Dictionary = new Dictionary<T, LinkedListNode<T>>();
              m_LinkedList = new LinkedList<T>();
          }
      
          public bool Add(T item)
          {
              if (m_Dictionary.ContainsKey(item)) return false;
              var node = m_LinkedList.AddLast(item);
              m_Dictionary.Add(item, node);
              return true;
          }
      
          void ICollection<T>.Add(T item)
          {
              Add(item);
          }
      
          public void Clear()
          {
              m_LinkedList.Clear();
              m_Dictionary.Clear();
          }
      
          public bool Remove(T item)
          {
              LinkedListNode<T> node;
              bool found = m_Dictionary.TryGetValue(item, out node);
              if (!found) return false;
              m_Dictionary.Remove(item);
              m_LinkedList.Remove(node);
              return true;
          }
      
          public int Count
          {
              get { return m_Dictionary.Count; }
          }
      
          public IEnumerator<T> GetEnumerator()
          {
              return m_LinkedList.GetEnumerator();
          }
      
          IEnumerator IEnumerable.GetEnumerator()
          {
              return GetEnumerator();
          }
      
      
          public bool Contains(T item)
          {
              return m_Dictionary.ContainsKey(item);
          }
      
          public void CopyTo(T[] array, int arrayIndex)
          {
              m_LinkedList.CopyTo(array, arrayIndex);
          }
      
      
          public virtual bool IsReadOnly
          {
              get { return m_Dictionary.IsReadOnly; }
          }
      
          public void UnionWith(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public void IntersectWith(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public void ExceptWith(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public bool IsSubsetOf(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public void SymmetricExceptWith(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public bool IsSupersetOf(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public bool IsProperSupersetOf(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public bool IsProperSubsetOf(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public bool Overlaps(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          public bool SetEquals(IEnumerable<T> other)
          {
              throw GetNotSupportedDueToSimplification();
          }
      
          private static Exception GetNotSupportedDueToSimplification()
          {
              return new NotSupportedException("This method is not supported due to simplification of example code.");
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2010-12-07
        • 2010-11-22
        • 2011-10-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-18
        相关资源
        最近更新 更多