我有一个对象列表(Books),这些对象如下所示:
Class Book
{
public string book_Name {get; set;}
public Dictionary<string,string> book_Dictionary {get; set;}
public Book(string book_Name, Dictionary<string,string> book_Dictionary)
{
this.book_Name = book.Name;
this.book_Dictionary = book_Dictionary;
}
}
我将这些Book对象编译成书籍列表,所以我有
List<Book> library;
我想浏览此列表并整理出任何重复的图书对象。 (重复的书籍将是与列表中的任何其他书籍具有相同名称和词典的书籍。)
要做到这一点,我正在尝试以下方法:
private List<Book> removeDuplicateBooks(List<Book> library)
{
List<Book> distinctLibrary = library
.GroupBy(x => new { x.book_Name, x.book_Dictionary })
.Select(g => g.First())
.ToList();
return distinctLibrary;
}
然而,看起来这并没有删除重复...我的猜测是groupBy以某种方式被抛出一个循环,因为其中一个字典?
编辑:删除歧义 - 当我说它不删除重复时,我的意思是返回的distinctLibrary与库相同(即使库确实包含重复的书籍)。
编辑:示例: 假设我的库包含以下Book对象:
bookNum1:
name: "book1",
dictionary: {
Key:"foo"
Value:"bar"
Key:"balloon"
Value:"red"
}
bookNum2:
name: "book2",
dictionary: {
Key:"foo"
Value:"bar"
Key:"balloon"
Value:"red"
}
bookNum3:
name: "book1",
dictionary: {
Key:"foo"
Value:"bar"
Key:"balloon"
Value:"red"
}
bookNum4:
name: "book1",
dictionary: {
Key:"fooey"
Value:"bar"
Key:"balloon"
Value:"red"
}
如果我通过removeDuplicates()函数放置这个库,我希望返回一个包含以下书籍对象的库:bookNum1,bookNum2,bookNum4
答案 0 :(得分:3)
Dictionary<TKey,TValue>
不会覆盖Equals
或GetHashCode
,这就是GroupBy
只会比较引用的原因。所有这些词典都是使用new Dictionary...
创建的,因此它们是不同的引用。您需要覆盖Equals
中的GetHashCode
和Book
和/或实施IEquatable<Book>
和/或提供自定义IEqualityComparer<Book>
(针对GroupBy
)。
public class Book : IEquatable<Book>
{
public string BookName { get; }
public Dictionary<string, string> BookDictionary { get; }
public Book(string bookName, Dictionary<string, string> bookDictionary)
{
this.BookName = bookName;
this.BookDictionary = bookDictionary ?? throw new ArgumentNullException(nameof(bookDictionary));
}
public bool Equals(Book other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
if (!string.Equals(BookName, other.BookName))
return false;
if (BookDictionary.Count != other.BookDictionary.Count)
return false;
return BookDictionary.All(kv => other.BookDictionary.ContainsKey(kv.Value)
&& other.BookDictionary[kv.Key] == kv.Value);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return Equals((Book) obj);
}
public override int GetHashCode()
{
unchecked
{
int dictHash = 17;
foreach (KeyValuePair<string, string> kv in this.BookDictionary)
{
dictHash = dictHash * 23 + kv.Key.GetHashCode();
dictHash = dictHash * 23 + (kv.Value ?? "").GetHashCode();
}
return ((BookName != null ? BookName.GetHashCode() : 0) * 397) ^ dictHash;
}
}
}
现在,您可以将Book
本身用作词典中的键或GroupBy
的参数:
List<Book> distinctLibrary = library
.GroupBy(book => book)
.Select(g => g.First())
.ToList();
现在你甚至可以使用效率更高(更简单):
List<Book> distinctLibrary = library.Distinct().ToList();
答案 1 :(得分:1)
如果要比较自定义类型,则必须实现IComparable接口。然后,这允许确定对象是否大于&#34;或者&#34;小于&#34;或者相等。
如何实现这取决于您的业务逻辑。
答案 2 :(得分:1)
您共享的主要方法和虚拟数据。
static void Main(string[] args)
{
Dictionary<string, string> dict = new Dictionary<string, string>()
{
{ "foo", "bar"},
{ "balloon", "red"}
};
Dictionary<string, string> dict2 = new Dictionary<string, string>()
{
{ "fooey", "bar"},
{ "balloon", "red"}
};
var books = new List<Book>();
books.Add(new Book("book1", dict));
books.Add(new Book("book2", dict));
books.Add(new Book("book1", dict));
books.Add(new Book("book1", dict2));
var distinctLib = RemoveDuplicateBooks(books);
}
Linq查询;
private static List<Book> RemoveDuplicateBooks(List<Book> library)
{
var distinctLib = from c in library
group c by new
{
c.book_Name,
c.book_Dictionary
} into temp
select new Book()
{
book_Name = temp.First().book_Name,
book_Dictionary = temp.First().book_Dictionary
};
return distinctLib.ToList();
}
返回;
Book1 , Book2 和 Book4
答案 3 :(得分:0)
由于您已经有了删除重复图书的方法,我建议您:
private void removeDuplicateBooks(List<Book> library)
{
foreach(Book b in library) {
// put book b in a new library
List<Book> distinctLibrary = library.FindAll(b);
// if you find more than once the book
if(distinctLibrary.Count > 1) {
// delete all copies of b and keep only one
library.RemoveAll(b);
library.Add(b);
}
}
}
注意:此方法不会返回新库,只会清除deafault库。