Логика коллекций Java / проблема избыточного кодирования - PullRequest
1 голос
/ 23 октября 2010

Ниже приведена реализация упражнения, которое меня попросили выполнить (см. Комментарии). Это работает, и причина, по которой я публикую это, состоит в том, что функция checkMiracle выглядит так, как будто она должна содержаться в гораздо меньшем цикле кода - я пишу то же самое плюс один десять раз. Проблема в том, что я не могу найти более короткий способ сделать это. Тогда у меня возникает вопрос: может ли кто-нибудь указать мне в каком-либо направлении, как сократить код в этом листинге, возможно, стоит подумать над тем, чтобы сделать его более компактным или «умным» способом его кодирования. Любая помощь приветствуется. (Лист упражнений находится на JCF, поэтому он заставляет нас кодировать это, используя коллекции)

/*A 10-digit decimal number N is said to be miraculous if it contains each of the ten decimal digits, and if
the 2-digit number consisting of the first two (most significant, i.e. leftmost) digits of N is divisible by
2, the 3-digit number consisting of the first three digits of N is divisible by 3, and so on up to and including
that N itself is divisible by 10. Write a program to discover a miraculous number (there really is one).
Proceed by making a list of the ten decimal digits, and repeatedly shuffling them until you chance upon an
arrangement that constitutes a miraculous number.
(Note: Type long rather than int is needed for 10-digit decimal integers.) */

import java.util.*;

public class Miracle {

 static private long miracleNum = 0;

 static private ArrayList<Integer> listing = new ArrayList<Integer>();

 static String castValue = "";


 public static void main(String[] args) {

  for(int i = 0; i < 10; i++) listing.add(i); 

  Collections.shuffle(listing);

  while(listing.get(0)==0) Collections.shuffle(listing); //make sure the number doesnt start with zero

  while(!(checkMiracle(listing))) Collections.shuffle(listing);//keep changing it until we get a miracle number



  for(long l : listing) castValue += l;

  miracleNum = Long.parseLong(castValue);

  System.out.println("Miracle num: " + miracleNum);


 }


 static public boolean checkMiracle(ArrayList<Integer> l) {


  long checkValue = Long.parseLong("" + l.get(0) + l.get(1));

  if(checkValue %2 != 0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2));

  if(checkValue %3 != 0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3));

  if(checkValue %4 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4));

  if(checkValue %5 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5));

  if(checkValue %6 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5) + l.get(6));

  if(checkValue %7 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5) + l.get(6) + l.get(7));

  if(checkValue %8 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5) + l.get(6) + l.get(7)+ l.get(8));

  if(checkValue %9 !=0) return false;


  checkValue = Long.parseLong("" + l.get(0) + l.get(1) + l.get(2) + l.get(3) + l.get(4) + l.get(5) + l.get(6) + l.get(7)+ l.get(8) + l.get(9));

  if(checkValue %10 !=0) return false;


  return true;


 }


}

Ответы [ 4 ]

3 голосов
/ 23 октября 2010

почему бы вам не собрать все условия внутри цикла?Затем вы можете просто добавить следующую цифру к числу, чтобы вычислить следующую.

String partial = Long.parseLong(l.get(0));
for (int i = 1; i < 10; ++i) {
  partial += Long.parseLong(l.get(i));
  if (Long.valueOf(partial) % (i+1) != 0)
    return false;
}
return true;

Кроме того, вы можете избежать использования строк, используя возведение в степень digit^(displacement).Необходимость решить подобную проблему с помощью коллекций выглядит нелепо ..

2 голосов
/ 23 октября 2010

Может быть удалить некоторое дублирование кода с помощью циклов:

private static boolean checkMiracleN(List<Integer> l, int n){
   long sum = 0;
   for (int i=0; i<n; i++)
       sum = sum * 10 + l.get(i);
   return sum % n == 0;
}

private static boolean checkMiracle(ArrayList<Integer> l){
    for (int n=2; n<=10; n++)
       if (!checkMiracleN(l, n) 
          return false;
    return true;
}
1 голос
/ 23 октября 2010

Используйте вспомогательную функцию, чтобы заменить повторяющийся код на цикл:

static public String GetNumberString(ArrayList<Integer> l, int numDigits)
{
    StringBuilder sb = new StringBuilder();

    for(int i = 0; i < numDigits; i++)
    {
        sb.Append(l.get(i));
    }
    return sb.ToString();
}


static public boolean checkMiracle(ArrayList<Integer> l) {

  long checkValue = 0;

  for (int i = 2; i < 10; i++)
  {
      checkValue = Long.parseLong(GetNumberString(l, i));
      if(checkValue % i != 0) return false;
  }
}

Это по-прежнему означает, что вы каждый раз создаете очень похожую строку.Улучшение будет заключаться в том, чтобы постепенно наращивать число на каждой итерации цикла, а не пересоздавать его каждый раз.

0 голосов
/ 23 октября 2010

Пара коротких путей, которые вы можете сделать. например если число четное, его последняя цифра должна быть четной

if (l.get (1)% 2 == 0) вернуть false;

если число кратно десяти, его последняя цифра должна быть '0'

if (l.get (9) == 0) вернуть false;

Если число кратно 3, сумма, если его цифры кратны трем (то же самое для 9)

Если число кратно 5, его последняя цифра должна быть 5 или 0.

В большинстве случаев вам не нужно * или%. Вам определенно не нужно создавать строку и анализировать ее.

...