【问题标题】:Is there clean syntax for checking if multiple variables all have the same value?是否有干净的语法来检查多个变量是否都具有相同的值?
【发布时间】:2011-07-27 01:29:32
【问题描述】:

我们有 n 个变量 X = {x1,x2,...xn} 它们不在任何结构中。

以 python 为例,我可以这样做:if (x1 == x2 == x3 == xn):

在java中我必须这样做:if((x1 == x2) && (x2 == x3) && (x3 == xn)):

你知道改进这种语法的简单方法吗? (想象一下很长的变量名和很多)

谢谢。

【问题讨论】:

  • 不是你要的,但这需要某种数据结构而不是一堆自变量。
  • 太糟糕了。我会调查的。谢谢!
  • 在 java 中,(x1 == x2 == x3 == x4) 将返回Test.java:8: 无法比较的类型:boolean 和 int System.out.println(x1 == x2 == x3 = = x4); ^ Test.java:8:无法比较的类型:布尔和整数 System.out.println(x1 == x2 == x3 == x4);
  • 我说在 python 中我们可以做到这一点 (x1 == blabla) Leo 你的意思是什么?
  • @Leo 如果您尝试使用一组布尔值来做到这一点,那就更加危险了。如果 x1,x2,x3,x4 是布尔值,它们将编译但有一个静默错误。 x1 == x2 == x3(x1 == x2) == x3 这与我们想要的非常不同!

标签: java


【解决方案1】:

如果您有很多这些变量,您是否考虑过将它们放在一个集合中而不是将它们作为单独的变量?那时有多种选择。

如果您发现自己经常这样做,您可能想要编写辅助方法,可能使用可变参数语法。例如:

public static boolean areAllEqual(int... values)
{
    if (values.length == 0)
    {
        return true; // Alternative below
    }
    int checkValue = values[0];
    for (int i = 1; i < values.length; i++)
    {
        if (values[i] != checkValue)
        {
            return false;
        }
    }
    return true;
}

glowcoder 提出的另一种方法是强制至少有一个值:

public static boolean areAllEqual(int checkValue, int... otherValues)
{
    for (int value : otherValues)
    {
        if (value != checkValue)
        {
            return false;
        }
    }
    return true;
}

在任何一种情况下,都使用:

if (HelperClass.areAllEqual(x1, x2, x3, x4, x5))
{
    ...
}

【讨论】:

  • 我认为areAllTheSame() 应该返回true。目前我想它会在values[0] 上窒息。
【解决方案2】:

你可以像这样创建一个实用方法:

public boolean allEqual(Object... objs) {
    if(objs.length < 2) return true; // 0 or 1 objects are all equal
    Object key = objs[0]; // pick one
    for(Object o : objs) if(!o.equals(key)) return false;
    return true;
}

另一种选择是

public boolean allEqual(Object key, Object... objs) {
    for(Object o : objs) if(!o.equals(key)) return false;
    return true;
}

为了简化很多样板逻辑。那就去吧

if(allEqual(x,x1,x2,x3))

显然,这两者是互斥的(它们显然是模棱两可的),但你可以 allEqualallEqualWithKey

【讨论】:

  • @glowcoder:我也考虑过这种形式......但是将所有值装箱可能最终会有点痛苦。我认为为了一些重载,我会分别对待每个原始类型。
  • +1 @Jon,虽然这样做的好处是更可重用。取决于应用程序,我想。
  • @Lord Torgamus:老实说,我很惊讶地看到不止几种类型需要这个。不过,我确实喜欢“强制至少一个论点” :)
  • 感谢大家的宝贵时间!顺便说一句,我的对象是 ArrayLists,我正在检查它们的大小。在过去的 10 分钟里,我学到的东西比过去一小时要多,我在网上寻找答案。再次感谢您!
  • @Jon 我现在可以看到代码审查。 “这个匿名的 Comparator 对象是什么,它有什么作用?”哦,这定义了 allEqual 实用程序的比较。 “那有什么作用?”哦,它使我们免于编写样板代码!
【解决方案3】:

类似于@Jon 的解决方案,但更短。

public static boolean areAllTheSame(int value, int... values) {
    for (int i: values) if(value != i) return false;
    return true;
}

【讨论】:

  • 缩短的一半原因是在一行上放了很多东西而不是使用大括号——我在生产代码中永远不会这样做。我已经在我的代码中编辑了“强制至少一个参数”版本,最初由glowcoder显示。
  • @Jon 我在看到你的编辑之前写了这个。我不赞成在新行上用大量 { } 填充代码。但是,我只会使用一个衬里来进行最简单的操作。
  • 这不是“填充代码”——它让事情变得绝对清晰,IMO。曾经被“缩进说谎,这是一个 if 语句,后面有一个语句,然后是另一个语句”的错误所咬伤,我不打算重复同样的错误。当然,您可以将左大括号放在引导线的末尾...
  • @Jon 我倾向于使用 IDE 来突出显示身份是否在说谎。我们所有的开发人员都已启用此功能。 ;) 我同意;你应该做你认为最清楚的事情。我倾向于发现符号越少越好(尽管我更喜欢有意义的事物名称)
【解决方案4】:

你可以写一个方法让这看起来不那么麻烦:

boolean areAllEqual(Object... values) {
    if (values.length < 2) {
        return true;
    }

    for (int i = 1; i < values.length; i++) {
        if (!values[i].equals(values[0])) {
            return false;
        }
    }

    return true;
}

像这样使用它:

if (areAllEqual(x1, x2, x3, x4, x5)) {
    // do something
}

编辑太慢了...! :-(

【讨论】:

    【解决方案5】:

    很遗憾,不,没有可用的语法糖。这是对 Java 的常见抱怨。

    【讨论】:

    • 嗯,也许那时只在我的大学里很常见?感谢@Jon 提供另一种观点。
    • 在几年的 Java 中从未需要过这个。很可爱,但还有很多其他地方的语法让我更疯狂:)
    • 如果我必须在这个和闭包之间做出选择...... :)
    • 我认为一个相关的并且可能更常见的糖请求是像 if(0 &lt; x &lt; 10) 这样的东西来替换 if(0 &lt; x &amp;&amp; x &lt; 10)
    • 对于反对者和未来反对者:我考虑删除这篇文章,但标题和正文都专门询问语法,而不是检查相等性的聪明算法。如果有的话,原来的标题稍微更明确一些。
    【解决方案6】:
    /*
    * reference - basic String to compare against
    * entries - all other objects for comparison
    */
    public static boolean allEqual(String reference, String... entries) {
            return Arrays.stream(entries)
                    .allMatch(entry -> Objects.equals(reference, entry));
    }
    
    /*
    * Method can be generalized to use <T> instead of String
    */
    public static <T>boolean allEqual(T reference, T... entries) {
        return Arrays.stream(entries)
                .allMatch(entry -> Objects.equals(reference, entry));
    }
    
    public static void main(String[] args) {
        System.out.println(allEqual("X", "X", "X", "X")); // true
        System.out.println(allEqual("X", "X", "Y"));      // false
        System.out.println(allEqual("X"));                // true
    
        System.out.println(allEqual(10, 10, 9));          // false
        System.out.println(allEqual(10, 10));             // true
        System.out.println(allEqual(10, new Integer[] {10, 10, 10})); // true
    }
    

    【讨论】:

    • 很高兴看到有人仍在回答旧问题并提供最新答案。如果你能添加一些关于如何使用你的方法以及它是如何工作的解释,那就更好了。
    • 对不起,没有考虑解释。我已经更新了sn-p。我希望它现在更具可读性。
    【解决方案7】:

    如果你不喜欢打字,你可能会失去嵌套的括号:

    if(x1 == x2 && x2 == x3 && x3 == xn);
    

    【讨论】:

    • 你说得对,对不起。我误解了运算符优先级link
    【解决方案8】:

    实现此目的的另一种快速方法是通过array -> List -> HashSet 转换路线,如:

    标准 Java:

    if(new HashSet<Object>(Arrays.asList(x1, x2, x3, x4, x5)).size() == 1) {
    
    }
    

    谷歌番石榴:

    if(Sets.newHashSet(Ints.asList(x1, x2, x3, x4, x5)).size() == 1) {
    
    }
    

    不过,上述解决方案本身看起来并不太干净,因此绝对应该将其隔离到一个具有合理名称的单独实用程序方法中(在这种情况下,使用 Peter Lawrey 或 Jon 可能会更好首先是 Skeet 的解决方案)。

    我还希望这种方法至少会带来很小的性能损失,因为很明显多个Collections 必须被实例化和填充。

    所以重申一下 - 仅当您一心想打单线时才使用此解决方案。

    【讨论】:

      【解决方案9】:

      在 Java 8 中,这可以使用 Stream 以单行方式完成:

      boolean allEqual = Stream.of(x1, x2, x3, x4).distinct().count() == 1;
      

      基本上distinct 通过检查每个元素是否相等来过滤流,以便只保留唯一元素。如果过滤后只剩下一个元素,则表示所有原始元素都是相等的。

      【讨论】:

        【解决方案10】:

        我喜欢已经建议的样板逻辑,但通常列表中的任何参数都可以是null,这可能会导致NullPointerException 被抛出。因此,我们应该首先测试null,并在适当的时候使用== 来比较对象引用:

        public static boolean allEqual(Object key, Object... objs) {
            for(Object o : objs)
                if((key != null && !key.equals(o)) || key != o) return false;
            return true;
        }
        

        【讨论】:

        • 请注意,Object... objs 至少需要两个参数才能解释为给定单个 null 值的数组。因此,在二值比较的情况下,使用标准 java 命令,或者将以下内容添加到方法的开头objs = objs == null ? new Object[]{ null } : objs;
        【解决方案11】:

        org.apache.commons.lang3.BooleanUtils public static boolean and(final boolean...array)

        【讨论】:

          【解决方案12】:

          只是为了更新这些答案 (Java SE 9)。

           Set.of(x1,x2,...xn).size() == 1
          

          对数学家来说非常有意义。 (在这种情况下,我称自己为数学家。)

          (很明显,Integers、Integer[]Set 以及 Set 的内部可能存在另一种拳击开销。)

          编辑: Stuart Marks 指出如果有重复元素,Set.of 会抛出 IllegalArgumentException。替代方案:

          Set.copyOf(Arrays.asList(x1,x2,...xn)).size() == 1
          

          或者取决于你对干净的定义:

          copyOf(asList(x1,x2,...xn)).size() == 1
          

          (假设静态导入过多。)

          【讨论】:

            【解决方案13】:

            使用以下代码,您可以识别 Map 重复值:

                public static void main(String[] args) {
                    int a = 1;
                    int b = 2;
                    int c = 1;
                    int d = 3;
            
                    Collection<Integer> collectionOfValues = List.of(a, b, c, d);
            
                    Map<Integer, List<Integer>> groupedByUniqueKeys = collectionOfValues.stream()
                        .collect(
                            groupingBy(
                                Function.identity()));
            
                    System.out.println(groupedByUniqueKeys);
                    // {1=[1, 1], 2=[2], 3=[3]}
                }
            

            1 的映射将包含具有相等值的变量的值(ac)。

            【讨论】:

            • 但这不是问题。
            猜你喜欢
            • 2019-06-30
            • 2021-03-22
            • 1970-01-01
            • 1970-01-01
            • 2012-11-21
            • 2014-02-03
            • 1970-01-01
            • 2012-07-01
            • 1970-01-01
            相关资源
            最近更新 更多