如何检查所有列表项是否具有相同的值并将其返回,或者如果没有,则返回“ otherValue”?


121

如果列表中的所有项目都具有相同的值,那么我需要使用该值,否则需要使用“ otherValue”。我想不出一种简单明了的方法。

另请参见简洁的编写循环的方式,该方式对于集合中的第一项具有特殊的逻辑。


在您而面露注意吸气,我会与阿尼的答案去stackoverflow.com/questions/4390232/...
二进制杞人忧天

5
如果因为列表为空而没有第一个值,您想怎么办?在这种情况下,它是真实的,“在列表中的所有项具有相同的价值” -如果你不相信我,我找一个不!您没有定义在这种情况下该做什么。应该抛出异常,返回“ other”值,还是什么?
埃里克·利珀特

@Eric,很抱歉,如果列表为空,则应返回“其他”值
Ian Ringrose 2010年

Answers:


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

我能想到的最干净的方法。您可以通过内联val使其成为一线式,但是First()将被评估n次,从而使执行时间加倍。

要合并注释中指定的“空集”行为,只需在上述两行之前添加一行:

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

1
+1,如果.Any值不同,会使用允许枚举提前退出吗?
杰夫·绪方

12
@adrift:All只要碰到x序列中的元素就会终止x.Value != val。同样,Any(x => x.Value != val)只要x到达序列中的元素就会终止x.Value != val。也就是说,无论是AllAny展“短路”类似于&&||(这是什么有效AllAny有)。
杰森2010年

@杰森:完全是。All(condition)实际上是!Any(!condition),并且一旦知道答案,对其中任一个的求值都会终止。
KeithS 2010年

4
微优化:return yyy.Skip(1).All(x=>x.Value == val) ? val : otherValue;
Caltor

100

对所有条件均进行良好的快速测试:

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

1
Class尽管它应该与结构一起使用,但它不能与任何一起使用。不过,非常适合用于原始类型的列表。
安德鲁·贝克

2
比KeithS的解决方案IMO +1清洁得多。collection.Distinct().Count() <= 1 如果要允许空集合,则可能要使用 。
3dGrabber 2013年

4
要小心,.Distinct()并不总是按预期-尤其是当你使用对象,看到这个问题。在这种情况下,您需要实现IEquatable接口。
马特

16
是的,比较干净,但是在一般情况下性能较差;确保Distinct()遍历集合中的每个单个元素一次,并且在每个元素都不相同的最坏情况下,Count()将遍历整个列表两次。Distinct()还会创建一个HashSet,因此其行为可以是线性的,而不是NlogN或更糟,这会增加内存使用率。All()在所有元素相等的最坏情况下进行一次完整通过,并且不创建任何新集合。
KeithS 2014年

1
@KeithS就像我希望您现在意识到的那样,Distinct根本不会遍历集合,而Count将通过Distinct的迭代器进行一次遍历。
NetMage

22

尽管您当然可以使用现有的序列运算符来构建这样的设备,但在这种情况下,我倾向于将其编写为自定义序列运算符。就像是:

// 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;
}

这很清楚,简短,涵盖了所有情况,并且不会不必要地创建序列的额外迭代。

使之成为一种可行的通用方法IEnumerable<T>是一项练习。:-)


举例来说,假设您有一系列可为空的值,并且提取的值也是可为空的值。在这种情况下,序列可能为空,或者序列中的每个项目的提取值都可能为空。聚结,在这种情况下,将返回other时,null实际上是(推测)正确的反应。说功能是T Unanimous<U, T>(this IEnumerable<U> sequence, T other)或类似的签名,会使它变得有些复杂。
安东尼·佩格拉姆

@Anthony:确实,这里有很多并发症,但是很容易解决。为了方便起见,我使用可为null的int,这样就不必声明“我已经看过第一项”标志。您可以轻松地声明标志。另外,我使用“ int”而不是T,因为我知道您总是可以比较两个int是否相等,而两个T却不是这样。这比全功能的通用解决方案更像是解决方案的草图。
埃里克·利珀特

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

或者,如果您担心要为每个元素执行First()(可能是有效的性能问题):

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

@KeithS-这就是为什么我添加了答案的第二部分。在小型集合上,调用First()很简单。在大型馆藏中,这可能会成为一个问题。
贾斯汀·尼斯纳

1
“在小型集合中,调用First()很简单。” -这取决于收藏的来源。对于简单对象的列表或数组,您绝对正确。但是,某些可枚举对象不是有限的内存缓存基元集。每次使用First()评估First()时,代表的集合或通过算法级数计算产生的枚举数(例如Fibonacci)将变得非常昂贵。
KeithS

5
或更糟糕的是,如果查询是数据库查询,并且每次调用“ First”都会再次命中数据库。
埃里克·利珀特

1
当您进行一次迭代(例如从文件读取)时,情况会变得更糟。因此,Ani从其他线程获得的答案似乎是最好的。
Alexei Levenkov 2010年

@Eric-来吧 每个元素三次访问数据库没有错... :-P
Justin Niessner 2010年

3

这可能已经晚了,但是基于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

使用LINQ的替代方法:

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

我发现HashSet<T>,与最多6,000个整数相比,使用起来更快:

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

首先,这可能会产生大量垃圾。而且,与其他LINQ答案相比,它还不清楚,但与扩展方法的答案相比,它要慢。
伊恩·林罗斯

真正。但是,如果我们要讨论确定一小部分值是否全部相同,则不会造成太多浪费。当我运行此程序并在LINQPad中运行LINQ语句以获取少量值时,HashSet更快(使用Stopwatch类进行计时)。
ƉiamondǤeezeƦ

如果从命令行在发布版本中运行它,则可能会得到不同的结果。
伊恩·林罗斯

创建了一个控制台应用程序,发现HashSet<T>最初比在我的答案中使用LINQ语句要快。但是,如果我循环执行此操作,则LINQ更快。
ƉiamondǤeezeƦ

此解决方案的最大问题是,如果您使用自定义类,则必须实现自己的GetHashCode(),这很难正确完成。有关更多详细信息,请参见:stackoverflow.com/a/371348/2607840
卡梅伦


-1

如果数组是如下所示的多维类型,则我们必须在linq下面编写以检查数据。

示例:这里元素为0,我正在检查所有值是否为0。
ip1 =
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";   
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.