C#中LinkedHashSet(Java)的等价物是什么?
答案 0 :(得分:10)
我完成了未完成的方法,并且通常打磨了“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方法。使用风险由您自己承担 我希望有人觉得这很有用。 :)
答案 1 :(得分:8)
C#中没有直接的等价物。要使用的适当类取决于所需的行为。 HashSet
类将保留元素的唯一性。您可能还想查看SortedSet
和SortedDictionary
。
C#中没有类将链接列表与Set数据结构中所需的唯一性组合在一起,因此如果您需要这两种行为,那么您将需要构建自己的行为。
答案 2 :(得分:5)
我已经简要地实施了一个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.");
}
}
答案 3 :(得分:4)
HashSet完成这项工作,因为它几乎等同于Java中的LinkedHashSet。 HashSet由链表支持 - 尽管文档没有明确声明它保留了订单,或者它是由基于数组的链表支持的。您可以从the source code看到实现是LinkedHashSet。
不允许像Java LinkedHashSet一样重复。这个和LinkedHashSet之间的一个区别是,如果从集合中删除某些东西,它只会在元素中将元素标记为空闲,因此在remove()之后添加一个项目会在“追加”之前先填充空数组插槽。解决这个问题的方法是调用TrimExcess()方法。因此,虽然在许多用例中它并不完全相同,例如序列化和反序列化以及有效的不可变集一旦创建就很有效。
您始终可以子类化并覆盖remove()以始终调用TrimExcess()以获得相同的行为。为清晰起见,您可以将类命名为LinkedHashSet!
handle
输出:
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();
}
}
}