如何将我的9个if语句压缩成一个

时间:2018-04-30 19:41:50

标签: java

我想知道所有一位数字可以分割的最小数字是什么,而不是查找它我创建了这个。

public static void main(String[] args) {

    for (int i = 100; i < 10000; i++) {

        if (i % 2 ==0) {

            if (i % 3 ==0) {

                if (i % 4 ==0) {

                    if (i % 5 ==0) {

                        if (i % 6 ==0) {

                            if (i % 7 ==0) {

                                if (i % 8 ==0) {

                                    if (i % 9 ==0) {

                                        System.out.println(i);

                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

如您所见,我在if语句x9中有一个if语句。代码工作但我想使用数组压缩我的if语句来使我的if语句像这样,但它不起作用。

 if (i % x[1, 2, 3, 4, 5, 6, 7, 8]) {
 System.out.println(i);
 break;
 }

有什么建议吗?

13 个答案:

答案 0 :(得分:153)

首先,你会认为你可以通过在%运算符的右侧放置2到9的乘积来一次测试所有这些。

if (i % (2 * 3 * 4 * 5 * 6 * 7 * 8 * 9) == 0)

但由于某些数字包含其分解中的先前数字,因此您应使用较低的数字,特别是最小公倍数。 8是2和4的倍数,9是3的倍数,如果产品中有8和9,那么也会覆盖6(2 * 3)。

if (i % (5 * 7 * 8 * 9) == 0)

原来是2520,这是最不常见的倍数。使用2520更具可读性,并在评论中解释为何使用此数字。

/**
 * The goal is to test if the number is a multiple of all integers
 * from 2 through 9.  Mathematically, the least common multiple to is a
 * multiple of all its input numbers.  Here, the LCM of 2, 3, ..., 9 is 2520.
 */
public static final int LCM_2_THRU_9 = 2520;

我宣布了一个常数,我会在这里使用它:

if (i % LCM_2_THRU_9 == 0)

答案 1 :(得分:84)

试试这个。

for (int i = 100; i < 10000; ++i) {
    int x = i;
    if (IntStream.of(2, 3, 4, 5, 6, 7, 8, 9).allMatch(k -> x % k == 0)) {
        System.out.println(i);
        break;
    }
}

-> 2520

或者你可以把它写成一个声明。

int result = IntStream
    .range(100, 10000)
    .filter(i -> IntStream.of(2, 3, 4, 5, 6, 7, 8, 9).allMatch(k -> i % k == 0))
    .findFirst()
    .getAsInt();

System.out.println(result);

-> 2520

答案 2 :(得分:47)

如前所述,写下你想要做的最好的方法可能就是检查2到9的产品。

但是,要回答关于如何压缩if语句的问题;嵌套的if语句等同于逻辑运算符AND,因此您也可以按以下方式编写if语句:

one

答案 3 :(得分:42)

你为什么不......

  

反转IF?

public static void main(String[] args) {

    for (int i = 100; i < 10000; i++) {

        //If value is not valid, continue to next value
        if (i % 2 != 0) continue;
        if (i % 3 != 0) continue;
        if (i % 4 != 0) continue;
        if (i % 5 != 0) continue;
        if (i % 6 != 0) continue;
        if (i % 7 != 0) continue;
        if (i % 8 != 0) continue;
        if (i % 9 != 0) continue;

        //Valid value found. Print and break out of the loop.
        System.out.println(i);
        break;
    }
}

或者,上述代码可以进一步重构为:

public static void main(String[] args) {
    for (int i = 100; i < 10000; i++) {
        if (isPrintable(i)) {
            System.out.println(i);
            break;
        }
    }
}

private static boolean isPrintable(int value) {
    return value % 2 == 0
           && value % 3 == 0
           && value % 4 == 0
           && value % 5 == 0
           && value % 6 == 0
           && value % 7 == 0
           && value % 8 == 0
           && value % 9 == 0;
}

此外,根据@ TeePeemm的建议,isPrintable()可以缩减为:

private static boolean isPrintable(int value) {
    for (int divisor = 2; divisor < 10; divisor++) {
        if (value % divisor != 0) return false;
    }
    return true;
}

1。如其他答案所示,也有基于语言的快捷方式。我同意他们的意见。

2。许多答案使用数字的LCM来使代码简洁,但这是一个等待咬人的休眠错误。循环执行完全改变,可以通过注释掉break;来看到。看似简单的解决方案引入了一个微妙的潜在错误。

答案 4 :(得分:20)

在Java 8及更高版本中,您可以使用Stream方法(特别是使用IntStream)。

首先,我们使用IntStream.rangeClosed(2, 9)(或等效地,IntStream.range(2, 10))来获取从Integer开始并以2结尾的连续9的流(包括的)。我们可以使用boolean将此流转换为.allMatch(...),当且仅当每个流元素符合某些条件时,才返回true。所需标准以lambda expressionn -> i % n == 0的形式提供。这可以作为(Integer n) -> (i % n == 0)详细编写,因此lambda表达式从名为Integer的流中将n作为输入,并返回i(循环计数器)是否可以整除按n。因此,如果.allMatch(n -> i % n == 0)可以被流中的每个true整除,i会返回Integer

我们需要再做一次修改:lambda表达式中使用的变量(例如i)必须有效最终

  

一个变量或参数,其值在初始化后永远不会改变,实际上是最终的。 (Oracle documentation

然而,循环计数器i 有效地最终,因为它在每次迭代时都会递增(因此重新分配)。解决方案是在循环内声明一个新变量int x = i;,以便x仅在其范围内分配一次(即循环的一次迭代)。因此,x 实际上是最终的,可以在lambda表达式中使用。

这是最终的解决方案:

import java.util.stream.IntStream;

public static void main(String[] args) {
    for (int i = 100; i < 10000; i++) {
        int x = i; // x is effectively final
        if (IntStream.rangeClosed(2, 9).allMatch(n -> x % n == 0)) {
            System.out.println(i);
            break;
        }
    }
}

答案 5 :(得分:18)

更简单的方法:

    public static void main(String[] args) {
        for (int i = 100; i <= 100000; i++) {
            if (isDivisible(i)) {
                System.out.println("Divisible by numbers 2...9: " + i);
                break;
            }
        }
    }

使用相同类型的结构,主要方法变为:

/companies/12/employees/209/posts/5
/companies/11/employees/209/posts/5

答案 6 :(得分:16)

您基本上在做的是尝试找到i LCM 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9if (i % (2 * 3 * 4 * 5 * 6 * 7 * 8 * 9) == 0) { System.out.println(i); break; } 。最初,您可能只想写

8 = 2*2*2, 4 = 2*2, 6 = 2*3

如果所有数字都是互质的,那将是真的。这意味着他们没有任何共同因素。但在这种情况下,这些数字不是互质的,而且有共同的因素。与3 = 1 * 3 , 6 = 2*3, 9 = 3*9一样,所有人都有2. LCM都有3.所以基本上我们必须使用2,3,4,5,6,7,8,9数字2,3,4,5,6,7,8,9。请参阅以下编辑以更正上述公式。

数字2520的最小公倍数(最小公倍数)= if ( i % 2520 == 0) { System.out.println(i); break; } 。 所以通过所有测试用例的正确公式是

if(i % 9 == 0 && i % 8 ==0 && i % 7 == 0 && i % 5 == 0) {
   System.out.println(i);
   break;
}

另一种使用的解决方案就是检查以下所有条件:

ImageBackground

答案 7 :(得分:12)

这个问题实际上是双重的:第一部分是,如何将具有相似条件的9 if语句压缩为一些更易读的形式。另一个也许是无意识的问题是,如何将“单位数字的LCM”这样的东西添加到代码中。让我们从后者开始,然后转到下面的前者。

Google的结果

如果您的程序中需要 这个数字(而不是程序计算它的唯一目的),您应该通过必要的最简单的方法获取它(在这种情况下,{{ 3}}),并在你的程序中包含一个常量,或许可以对数字的来源进行一些评论。

如果您不能找到它,请尝试自己计算(如rgettman所做),并再次将其包含为常量。如果失败或花费太多时间,请编写一次性程序来计算数字,但不要使用常量使其成为更大程序的一部分。不过,将一次性代码存储在某处是个好主意。评论可能是正确的地方。

迭代数组

现在是关于压缩if语句。

有使用流的解决方案,但在您的情况下,简单的数组可能会更好。这段代码也更通用,您可以轻松地将它移植到几乎任何语言,并且它不以数字方式绑定(您可以使用任何数组)。奖励点 - 任何人都应该理解它。

static boolean divisibleByAll(int n, int[] divisors) {
    for (int d : divisors) {
        if (n % d != 0) {
            return false;
        }
    }
    return true;
}

static int lcmOfSingleDigits() {
    int[] divisors = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (int i = 100; i < 10000; i++) {
        if (divisibleByAll(i, divisors)) {
            return i;
        }
    }
    return -1;  // Perhaps better to throw an exception
}

public static void main(String args[]) {
    System.out.println("Smallest number divisible by all one digit numbers: " +
                       lcmOfSingleDigits());
}

使用Streams

大多数Java-ish解决方案,这是您应该在实践中使用的解决方案 - 除非您需要非Java程序员来阅读您的代码。由saka1029和pkpnd的回答涵盖,所以我不再重复了。

答案 8 :(得分:6)

我认为您可以使用LCM (Least Common Multiple)(1,2,3,4,5,6,7,8,9)= 2520,如下所示:

if (i % 2520 == 0) {
    System.out.println(i);
    break;
}

答案 9 :(得分:3)

如果您尝试使用1到20或1到30之间的数字,您的循环将花费很长时间。您可以直接计算least common multiple

package stackOverflow;
import java.util.stream.LongStream;

public class NumberTheory
{

    public static void main(String[] args) {
        System.out.println(gcd(15, 3) == 3);
        System.out.println(gcd(13, 11) == 1);
        System.out.println(gcd(60, 24) == 12);
        System.out.println(gcd(1071, 462) == 21);
        System.out.println(gcd(462, 1071) == 21);
        System.out.println(gcd(new long[] { 10, 12, 24, 60 }) == 2);
        long[] oneToNine = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        System.out.println(gcd(oneToNine) == 1);
        System.out.println(lcm(oneToNine));
        long[] oneToTwenty = LongStream.range(1, 21).toArray();
        System.out.println(lcm(oneToTwenty));
    }

    /**
     * Calculates the greatest common divisor of 2 numbers which are not all zero. (see
     * https://en.wikipedia.org/wiki/Greatest_common_divisor)
     * 
     * Recursive version of Euclidean algorithm (https://en.wikipedia.org/wiki/Euclidean_algorithm)
     * 
     * @param m
     * @param n
     * @return greatest common divisor of m and n
     */
    public static long gcd(long m, long n) {
        if (m == 0 || n == 0) {
            return m + n;
        } else {
            return gcd(n, m % n);
        }
    }

    /**
     * Calculates the greatest common divisor of n numbers. The array should have at least one number which isn't zero.
     * 
     * @param numbers
     * @return greatest common divisor of numbers
     */
    public static long gcd(long[] numbers) {
        long result = numbers[0];
        for (int i = 1; i < numbers.length; i++) {
            result = gcd(result, numbers[i]);
        }
        return result;
    }

    /**
     * Calculates the least common multiple of 2 numbers which are both non zero. see
     * https://en.wikipedia.org/wiki/Least_common_multiple
     * 
     * @param m
     * @param n
     * @return least common multiple of m and n
     */
    public static long lcm(long m, long n) {
        return m * (n / gcd(m, n));
    }

    /**
     * Calculates the least common multiple of n numbers. The array should have at least one number and shouldn't contain
     * any zero.
     * 
     * @param numbers
     * @return least common multiple of numbers
     */
    public static long lcm(long[] numbers) {
        long result = numbers[0];
        for (int i = 1; i < numbers.length; i++) {
            result = lcm(result, numbers[i]);
        }
        return result;
    }
}

输出:

true
true
true
true
true
true
true
2520
232792560

答案 10 :(得分:3)

虽然这可能不是最理想的,但它会真正浓缩你的陈述:

void nearest(double a, double b, double x, double y, double *ecos_ret, double *esin_ret) {
    double ax = fabs(a*x);
    double by = fabs(b*y);
    double r  = b*b - a*a;
    double c, d;
    int switched = 0;

    if (ax <= by) {
        if (by == 0) {
            if (r >= 0) { *ecos_ret = 1; *esin_ret = 0; }
            else        { *ecos_ret = 0; *esin_ret = 1; }
            return;
        }
        c = (ax - r) / by;
        d = (ax + r) / by;
    } else {
        c = (by + r) / ax;
        d = (by - r) / ax;
        switched = 1;
    }

    double cc = c*c;
    double D0 = 12*(c*d + 1);      // *-4
    double D1 = 54*(d*d - cc);     // *4
    double D  = D1*D1 + D0*D0*D0;  // *16

    double St;
    if (D < 0) {
        double t = sqrt(-D0);             // *2
        double phi = acos(D1 / (t*t*t));
        St = 2*t*cos((1.0/3)*phi);        // *2
    } else {
        double Q = cbrt(D1 + sqrt(D));    // *2
        St = Q - D0 / Q;                  // *2
    }

    double p    = 3*cc;                          // *-2
    double SS   = (1.0/3)*(p + St);              // *4
    double S    = sqrt(SS);                      // *2
    double q    = 2*cc*c + 4*d;                  // *2
    double l    = sqrt(p - SS + q / S) - S - c;  // *2
    double ll   = l*l;                           // *4
    double ll4  = ll + 4;                        // *4
    double esin = (4*l)    / ll4;
    double ecos = (4 - ll) / ll4;

    if (switched) {
        double t = esin;
        esin = ecos;
        ecos = t;
    }

    *ecos_ret = copysign(ecos, a*x);
    *esin_ret = copysign(esin, b*y);
}

对于每个i,我们使用内部循环j对每个数字从2到9进行模数化。我们将每个模数结果添加到余数变量。

在内循环结束时,只有当这个i的所有模数都为零时,余数仍然为零。

答案 11 :(得分:2)

正如其他几个人所提到的,你要做的是计算数字1,2,3,...,9的least common multiple

但你怎么在电脑里这样做?首先,您需要知道如何计算两个数字的greatest common divisor

repositories {
    jcenter()
    mavenCentral()
    maven { url 'https://maven.google.com' }
    google()
}

现在,两个数字的最小公倍数可以用它们最大的公约数用一个简单的公式计算:

function gcd2(a, b)
    while b ≠ 0
        t := b; 
        b := a mod b; 
        a := t; 
    return a;

(a和b都为零的特殊情况是必要的,以避免被零除。)

最后,function lcm2(a, b) if a = 0 and b = 0 return 0; else return abs(a*b) / gcd2(a,b); ,为了计算两个以上数字的最小公倍数,迭代一个列表:

LCM(a,b,c) = LCM(LCM(a,b),c)

将伪代码转换为Java是一种练习。

答案 12 :(得分:2)

好吧,这可能不是最好的方法,但我想用一组任意数字试一试。

public interface Divisor {
    boolean isDivisible(Long value);
}

public static main(String[] args) {
    LCMDivisor divisor = LCMDivisor.init()
            .addValue(2L)
            .addValue(3L)
            .addValue(4L)
            .addValue(5L)
            .addValue(6L)
            .addValue(7L)
            .addValue(8L)
            .addValue(9L);

    LongStream.range(1, 10000)
            .filter(divisor::isDivisible)
            .findFirst()
            .ifPresent(System.out::println);
}

所以我们创建一个对象Divisor,它有一个方法可以告诉你一个值是否可以自行整除。

通过从1到N创建Long of Longs来运行代码,过滤掉除数除数后不能整除的所有值,然后取第一个(按照你的&#39; break&#39;语句)。它返回一个Optional。如果存在值,则该值将打印到标准输出。

对于这个例子,根据上面的评论,我介绍了Divisor的一个实现,它存储了所有值的最小公倍数。初始化时,它的值为1;但每次添加新值时,它都会返回具有最小公倍数的Divisor的新实例。实现如下:

public class LCMDivisor implements Divisor {

    public final Long lcmValue;

    private LCMDivisor(Long lcmValue) {
        this.lcmValue = lcmValue;
    }

    public static LCMDivisor init() {

        return new LCMDivisor(1L);
    }

    public Boolean isDivisible(final Long value) {
        return value % lcmValue == 0;
    }

    public LCMDivisor addValue(final Long newValue) {

        return new LCMDivisor(lcm(newValue));
    }

    private Long lcm(final Long newValue) {
        return newValue * (lcmValue / gcd(newValue));
    }

    private Long gcd(final Long newValue) {

        Long greater = newValue < lcmValue ? lcmValue : newValue;
        Long lesser = newValue > lcmValue ? lcmValue : newValue;

        while (lesser > 0)
        {
            long temp = lesser;
            lesser = greater % lesser;
            greater = temp;
        }
        return greater;
    }
}