Làm thế nào để kiểm tra xem tất cả các mục trong danh sách có cùng giá trị và trả lại giá trị đó hay không hoặc trả về “Giá trị khác” nếu chúng không có?


122

Nếu tất cả các mục trong danh sách có cùng giá trị thì tôi cần sử dụng giá trị đó, nếu không tôi cần sử dụng “Giá trị khác”. Tôi không thể nghĩ ra một cách đơn giản và rõ ràng để làm điều này.

Xem thêm Cách gọn gàng để viết vòng lặp có logic đặc biệt cho mục đầu tiên trong bộ sưu tập.


Trên cơ sở thu hút sự chú ý khá táo bạo của bạn, tôi sẽ xem câu trả lời của Ani stackoverflow.com/questions/4390232/…
Binary Worrier

5
Điều gì bạn muốn xảy ra nếu không có giá trị đầu tiên vì danh sách trống? Trong trường hợp đó, đúng là "tất cả các mục trong danh sách đều có giá trị như nhau" - nếu bạn không tin tôi, hãy tìm cho tôi một cái mà không! Bạn không xác định phải làm gì trong tình huống này. Điều này có nên ném một ngoại lệ, trả về giá trị "khác" hay gì?
Eric Lippert

@Eric, xin lỗi khi danh sách trống, nó sẽ trả về giá trị "khác"
Ian Ringrose

Câu trả lời:


153
var val = yyy.First().Value;
return yyy.All(x=>x.Value == val) ? val : otherValue; 

Cách sạch sẽ nhất mà tôi có thể nghĩ ra. Bạn có thể làm cho nó trở thành một lớp lót bằng cách nội tuyến val, nhưng First () sẽ được đánh giá n lần, nhân đôi thời gian thực thi.

Để kết hợp hành vi "tập hợp trống" được chỉ định trong các nhận xét, bạn chỉ cần thêm một dòng nữa trước hai dòng trên:

if(yyy == null || !yyy.Any()) return otherValue;

1
+1, liệu việc sử dụng .Anycho phép để thoát sớm trong các trường hợp có các giá trị khác nhau?
Jeff Ogata

12
@adrift: Allsẽ kết thúc ngay sau khi nó chạm vào một phần tử xcủa trình tự x.Value != val. Tương tự, Any(x => x.Value != val)sẽ kết thúc ngay sau khi nó chạm vào một phần tử xcủa chuỗi x.Value != val. Đó là, cả hai AllAnybiểu hiện "đoản mạch" tương tự như &&||(hiệu quả là những gì đã AllAnyđang xảy ra).
jason

@Jason: chính xác. Tất cả (điều kiện) là hiệu quả! Bất kỳ (! Điều kiện) nào, và việc đánh giá một trong hai sẽ kết thúc ngay sau khi biết câu trả lời.
KeithS

4
Kích thích vi mô:return yyy.Skip(1).All(x=>x.Value == val) ? val : otherValue;
Caltor

101

Tốt bài kiểm tra nhanh cho tất cả bằng nhau:

collection.Distinct().Count() == 1

1
Điều này sẽ không hoạt động với bất kỳ Class, mặc dù nó sẽ hoạt động với cấu trúc. Tuy nhiên, tuyệt vời cho một danh sách các nguyên thủy.
Andrew Backer

2
+1 sạch hơn nhiều so với giải pháp của KeithS 'IMO. Bạn có thể muốn sử dụng collection.Distinct().Count() <= 1 nếu bạn muốn cho phép các bộ sưu tập trống.
3DGrabber

4
Hãy cẩn thận, .Distinct()không phải lúc nào cũng hoạt động như mong đợi - đặc biệt là khi bạn làm việc với các đối tượng, hãy xem câu hỏi này . Trong trường hợp đó, bạn cần triển khai giao diện IEquatable.
Matt

16
Rõ ràng hơn, có, nhưng hiệu suất kém hơn trong trường hợp trung bình; Distinction () được đảm bảo sẽ duyệt qua mọi phần tử trong tập hợp một lần và trong trường hợp xấu nhất là mọi phần tử đều khác nhau, Count () sẽ duyệt qua danh sách đầy đủ hai lần. Distinction () cũng tạo ra một HashSet để hành vi của nó có thể là tuyến tính chứ không phải NlogN hoặc tệ hơn, và điều đó sẽ làm tăng mức sử dụng bộ nhớ. Tất cả () tạo ra một lần vượt qua trong trường hợp xấu nhất là tất cả các phần tử đều bằng nhau và không tạo bất kỳ tập hợp mới nào.
KeithS

1
@KeithS Như tôi hy vọng bây giờ bạn nhận ra, Distinctsẽ không duyệt qua bộ sưu tập nào cả và Countsẽ thực hiện một lần duyệt qua Distincttrình lặp của.
NetMage

22

Mặc dù bạn chắc chắn có thể xây dựng một thiết bị như vậy từ các toán tử trình tự hiện có, nhưng trong trường hợp này, tôi sẽ có xu hướng viết thiết bị này như một toán tử trình tự tùy chỉnh. Cái gì đó như:

// Returns "other" if the list is empty.
// Returns "other" if the list is non-empty and there are two different elements.
// Returns the element of the list if it is non-empty and all elements are the same.
public static int Unanimous(this IEnumerable<int> sequence, int other)
{
    int? first = null;
    foreach(var item in sequence)
    {
        if (first == null)
            first = item;
        else if (first.Value != item)
            return other;
    }
    return first ?? other;
}

Điều đó khá rõ ràng, ngắn gọn, bao hàm tất cả các trường hợp và không tạo thêm các lần lặp lại của trình tự một cách không cần thiết.

Việc biến điều này thành một phương pháp chung hoạt động IEnumerable<T>được để lại như một bài tập. :-)


Ví dụ, giả sử bạn có một chuỗi các giá trị nullable và giá trị được trích xuất cũng là một giá trị có thể giải nén. Trong trường hợp đó, dãy có thể trống hoặc mọi mục trong dãy có thể có giá trị được trích xuất bằng rỗng. Coalescing, trong trường hợp này, sẽ trả về thời otherđiểm nullphản hồi thực sự là (có lẽ) chính xác. Giả sử hàm là T Unanimous<U, T>(this IEnumerable<U> sequence, T other)hoặc một số chữ ký như vậy, điều đó làm phức tạp nó một chút.
Anthony Pegram

@Anthony: Thật vậy, có rất nhiều phức tạp ở đây, nhưng chúng khá dễ dàng xử lý. Tôi đang sử dụng int nullable để thuận tiện để tôi không phải khai báo cờ "Tôi đã thấy mục đầu tiên rồi". Bạn có thể dễ dàng khai báo cờ. Ngoài ra, tôi đang sử dụng "int" thay vì T vì tôi biết rằng bạn luôn có thể so sánh hai int để có sự bằng nhau, điều này không đúng với hai Ts. Đây là một bản phác thảo của một giải pháp hơn là một giải pháp chung chung đầy đủ chức năng.
Eric Lippert

13
return collection.All(i => i == collection.First())) 
    ? collection.First() : otherValue;.

Hoặc nếu bạn lo lắng về việc thực thi First () cho mỗi phần tử (có thể là mối quan tâm về hiệu suất hợp lệ):

var first = collection.First();
return collection.All(i => i == first) ? first : otherValue;

@KeithS - Đó là lý do tại sao tôi thêm phần thứ hai vào câu trả lời của mình. Trên các tập hợp nhỏ, việc gọi First () là không bình thường. Trên các bộ sưu tập lớn, điều đó có thể bắt đầu là một vấn đề.
Justin Niessner

1
"Trên các bộ sưu tập nhỏ, việc gọi First () là không bình thường." - Điều đó phụ thuộc vào nguồn sưu tập. Đối với một danh sách hoặc một mảng các đối tượng đơn giản, bạn hoàn toàn đúng. Tuy nhiên, một số liệt kê không phải là tập hợp nguyên thủy được lưu trong bộ nhớ đệm hữu hạn. Một tập hợp các đại biểu, hoặc một điều tra viên thu được thông qua phép tính chuỗi theo thuật toán (ví dụ: Fibonacci), sẽ rất tốn kém khi đánh giá First () vào mọi thời điểm.
KeithS

5
Hoặc tệ hơn, nếu truy vấn là truy vấn cơ sở dữ liệu và việc gọi "First" sẽ truy cập lại cơ sở dữ liệu mỗi lần.
Eric Lippert

1
Nó trở nên tồi tệ hơn khi bạn lặp lại một lần như đọc từ tệp ... Vì vậy, câu trả lời của Ani từ chuỗi khác có vẻ tốt nhất.
Alexei Levenkov

@Eric - Thôi nào. Có gì sai với đánh cơ sở dữ liệu ba lần cho mỗi phần tử ... :-P
Justin Niessner

3

Điều này có thể muộn, nhưng một tiện ích mở rộng hoạt động cho các loại giá trị và tham chiếu như nhau dựa trên câu trả lời của Eric:

public static partial class Extensions
{
    public static Nullable<T> Unanimous<T>(this IEnumerable<Nullable<T>> sequence, Nullable<T> other, IEqualityComparer comparer = null)  where T : struct, IComparable
    {
        object first = null;
        foreach(var item in sequence)
        {
            if (first == null)
                first = item;
            else if (comparer != null && !comparer.Equals(first, item))
                return other;
            else if (!first.Equals(item))
                return other;
        }
        return (Nullable<T>)first ?? other;
    }

    public static T Unanimous<T>(this IEnumerable<T> sequence, T other, IEqualityComparer comparer = null)  where T : class, IComparable
    {
        object first = null;
        foreach(var item in sequence)
        {
            if (first == null)
                first = item;
            else if (comparer != null && !comparer.Equals(first, item))
                return other;
            else if (!first.Equals(item))
                return other;
        }
        return (T)first ?? other;
    }
}

1
public int GetResult(List<int> list){
int first = list.First();
return list.All(x => x == first) ? first : SOME_OTHER_VALUE;
}

1

Một giải pháp thay thế cho việc sử dụng LINQ:

var set = new HashSet<int>(values);
return (1 == set.Count) ? values.First() : otherValue;

Tôi nhận thấy việc sử dụng HashSet<T>nhanh hơn đối với danh sách lên tới ~ 6.000 số nguyên so với:

var value1 = items.First();
return values.All(v => v == value1) ? value1: otherValue;

Thứ nhất, điều này có thể tạo ra nhiều rác. Ngoài ra, câu trả lời của LINQ khác không rõ ràng hơn, nhưng chậm hơn thì phương thức mở rộng trả lời.
Ian Ringrose

Thật. Tuy nhiên, sẽ không nhiều nếu chúng ta đang nói về việc xác định xem một tập hợp nhỏ các giá trị có giống nhau hay không. Khi tôi chạy điều này và một câu lệnh LINQ trong LINQPad cho một tập hợp giá trị nhỏ, HashSet nhanh hơn (tính giờ bằng cách sử dụng lớp Đồng hồ bấm giờ).
Ɖiamond ǤeezeƦ

Nếu bạn chạy nó trong một bản phát hành từ dòng lệnh, bạn có thể nhận được các kết quả khác nhau.
Ian Ringrose

Đã tạo một ứng dụng bảng điều khiển và nhận thấy rằng HashSet<T>ban đầu nhanh hơn so với việc sử dụng các câu lệnh LINQ trong câu trả lời của tôi. Tuy nhiên, nếu tôi làm điều này trong một vòng lặp, thì LINQ sẽ nhanh hơn.
Ɖiamond ǤeezeƦ

Các lớn vấn đề với giải pháp này là nếu bạn đang sử dụng các lớp tùy chỉnh của bạn, bạn phải thực hiện riêng của bạn GetHashCode(), đó là khó khăn để làm một cách chính xác Xem: stackoverflow.com/a/371348/2607840 để biết thêm chi tiết.
Cameron

0

Một biến thể nhỏ về cách tiếp cận đơn giản ở trên.

var result = yyy.Distinct().Count() == yyy.Count();


3
Đây chính xác là một con đường khác. Điều này sẽ kiểm tra xem mọi phần tử trong danh sách là Duy nhất.
Mario Galea

-1

Nếu một mảng có kiểu multidimension như bên dưới thì ta phải ghi vào bên dưới linq để kiểm tra dữ liệu.

ví dụ: ở đây các phần tử là 0 và tôi đang kiểm tra tất cả các giá trị có phải là 0 hay không.
ip1 =
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

    var value=ip1[0][0];  //got the first index value
    var equalValue = ip1.Any(x=>x.Any(xy=>xy.Equals()));  //check with all elements value 
    if(equalValue)//returns true or false  
    {  
    return "Same Numbers";  
    }else{  
    return "Different Numbers";   
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.