Tôi có một danh sách nhỏ các byte và tôi muốn kiểm tra xem chúng đều có các giá trị khác nhau. Ví dụ, tôi có cái này:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Cách tốt nhất để kiểm tra xem tất cả các giá trị có khác biệt hay không?
Tôi có một danh sách nhỏ các byte và tôi muốn kiểm tra xem chúng đều có các giá trị khác nhau. Ví dụ, tôi có cái này:
List<byte> theList = new List<byte> { 1,4,3,6,1 };
Cách tốt nhất để kiểm tra xem tất cả các giá trị có khác biệt hay không?
Câu trả lời:
bool isUnique = theList.Distinct().Count() == theList.Count();
Đây là một cách tiếp cận khác hiệu quả hơn Enumerable.Distinct+ Enumerable.Count(hơn thế nữa nếu chuỗi không phải là một loại tập hợp). Nó sử dụng một HashSet<T>để loại bỏ các bản sao, rất hiệu quả trong việc tra cứu và có một thuộc tính đếm:
var distinctBytes = new HashSet<byte>(theList);
bool allDifferent = distinctBytes.Count == theList.Count;
hoặc cách tiếp cận khác - tinh tế và hiệu quả hơn -:
var diffChecker = new HashSet<byte>();
bool allDifferent = theList.All(diffChecker.Add);
HashSet<T>.Addtrả về falsenếu phần tử không thể được thêm vì nó đã có trong HashSet. Enumerable.Alldừng ở "false" đầu tiên.
Assert.IsTrue(samples.Add(AwesomeClass.GetUnique()));. Họ đã và đang :) 1 cho bạn Tim :)
bool allDifferent = theList.All(s => diffChecker.Add(s))
List.All(HashSet.Add)) dường như nhanh hơn nhiều so với hai kịch bản còn lại trong hầu hết các trường hợp
Được rồi, đây là phương pháp hiệu quả nhất mà tôi có thể nghĩ đến khi sử dụng .Net chuẩn
using System;
using System.Collections.Generic;
public static class Extension
{
public static bool HasDuplicate<T>(
this IEnumerable<T> source,
out T firstDuplicate)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
var checkBuffer = new HashSet<T>();
foreach (var t in source)
{
if (checkBuffer.Add(t))
{
continue;
}
firstDuplicate = t;
return true;
}
firstDuplicate = default(T);
return false;
}
}
Về cơ bản, điểm của việc liệt kê toàn bộ dãy hai lần là gì nếu tất cả những gì bạn muốn làm là tìm bản sao đầu tiên.
Tôi có thể tối ưu hóa điều này nhiều hơn bằng cách đặt cách viết hoa đặc biệt cho các chuỗi phần tử trống và đơn lẻ nhưng điều đó sẽ mất đi khả năng đọc / bảo trì với mức tăng tối thiểu.
sequence nên có source). Nhưng hoạt động tốt khi những điều này đã được sửa
if (!checkBuffer.Add(t)) { firstDuplicate = t; return true }ở trong vòng lặp.
Logic tương tự để Distinctsử dụng GroupBy:
var isUnique = theList.GroupBy(i => i).Count() == theList.Count;
theList.GroupBy(o => o.SomeProperty).Count() == theList.Count;trong khi Distinction () không cho phép điều đó.
Có nhiều giải pháp.
Và không nghi ngờ gì nữa, những bức ảnh đẹp hơn với việc sử dụng LINQ như "juergen d" và "Tim Schmelter" đã đề cập.
Tuy nhiên, nếu bạn không có "Độ phức tạp" và tốc độ, giải pháp tốt nhất sẽ là tự thực hiện nó. Một trong những giải pháp sẽ là tạo một mảng kích thước N (đối với byte là 256). Và lặp lại mảng và trên mỗi lần lặp sẽ kiểm tra chỉ số số phù hợp nếu giá trị là 1 nếu nó có, điều đó có nghĩa là tôi đã tăng chỉ số mảng và do đó mảng không khác biệt, nếu không tôi sẽ tăng ô mảng và tiếp tục kiểm tra .
Và một giải pháp khác, nếu bạn muốn tìm các giá trị trùng lặp.
var values = new [] { 9, 7, 2, 6, 7, 3, 8, 2 };
var sorted = values.ToList();
sorted.Sort();
for (var index = 1; index < sorted.Count; index++)
{
var previous = sorted[index - 1];
var current = sorted[index];
if (current == previous)
Console.WriteLine(string.Format("duplicated value: {0}", current));
}
Đầu ra:
duplicated value: 2
duplicated value: 7
Tôi kiểm tra xem IEnumerable (aray, list, v.v.) có phải là duy nhất như sau không:
var isUnique = someObjectsEnum.GroupBy(o => o.SomeProperty).Max(g => g.Count()) == 1;