Czy istnieje możliwość sumowania ArrayList bez zapętlenia


88

Czy istnieje możliwość sumowania ArrayListbez zapętlenia?

PHP dostarcza sum(array)sumę tablicy.

Kod PHP jest podobny

$a = array(2, 4, 6, 8);
echo "sum(a) = " . array_sum($a) . "\n";

Chciałem zrobić to samo w Javie:

List tt = new ArrayList();
tt.add(1);
tt.add(2);
tt.add(3);

2
A co jeśli ArrayListnie zawiera czegoś, co można „podsumować”? ArrayList i tablica niekoniecznie to to samo. Jeśli chodzi o sumowanie liczb w tablicy, jest to bardzo prosta pętla for po elementach i obliczanie skumulowanej sumy.
posdef

Funkcja PHP array_sumrównież wykonuje wewnętrzną pętlę, po prostu ukrywa ją przed użytkownikiem.
Paŭlo Ebermann

1
To rozsądne pytanie. W końcu napisanie pętli w celu znalezienia największego elementu na liście jest prawie równie trywialne, jednak java.util.Collections udostępnia metodę max ().
John Velonis,

1
Bardzo rozsądne pytanie, w końcu o to chodzi w metodach, prawda? Ponowne użycie :)
Ben Taliadoros,

Pętle są piękne.
Alex78191

Odpowiedzi:


156

Pewnego razu jest niedostępny (marzec 2014) będziesz mógł korzystać ze strumieni :

Jeśli masz List<Integer>

int sum = list.stream().mapToInt(Integer::intValue).sum();

Jeśli to int[]

int sum = IntStream.of(a).sum();

5
mapużywa pętli niejawnie
Nikos M.,

8
Możesz użyć rekurencji, aby nie używać pętli. : D (nie rób tego)
Caleb Fenton,

23

Następnie napisz to sam:

public int sum(List<Integer> list) {
     int sum = 0; 

     for (int i : list)
         sum = sum + i;

     return sum;
}

1
Lub rozszerzenie ArrayList za pomocą metody sum, dzięki czemu można ją wbudować we własną ArrayList.
Bueller

3
Podczas faktycznego dodawania po prostu przyjemniej jest użyć prostego pliku int. Korzystanie Integerz funkcji automatycznego boksu Java ma tutaj niewielką wartość . Ponadto za Integerkażdym razem tworzysz i odtwarzasz potencjalnie wiele nowych obiektów, ponieważ jest to Immutabletyp.
Java Drinker

10

Jedyną alternatywą dla używania pętli jest użycie rekurencji.

Możesz zdefiniować metodę, taką jak

public static int sum(List<Integer> ints) {
   return ints.isEmpty() ? 0 : ints.get(0) + ints.subList(1, ints.length());
}

Jest to bardzo nieefektywne w porównaniu do używania zwykłej pętli i może wybuchnąć, jeśli masz wiele elementów na liście.

Alternatywą, która pozwala uniknąć przepełnienia stosu, jest użycie.

public static int sum(List<Integer> ints) {
    int len = ints.size();
    if (len == 0) return 0;
    if (len == 1) return ints.get(0);
    return sum(ints.subList(0, len/2)) + sum(ints.subList(len/2, len));
}

Jest to równie nieefektywne, ale pozwoli uniknąć przepełnienia stosu.


Najkrótszym sposobem napisania tego samego jest

int sum = 0, a[] = {2, 4, 6, 8};

for(int i: a) {
    sum += i;
}

System.out.println("sum(a) = " + sum);

wydruki

sum(a) = 20

W kodzie brakuje wywołania sum () w pierwszej definicji rekurencyjnej. Druga definicja rekurencyjna nie zapobiega przepełnieniu stosu, zmniejsza to prawdopodobieństwo.
Teudimundo

1
@Teudimundo True, chociaż to nie zapobiega, maksymalny rozmiar listy to Integer.MAX_VALUE, a log2 to 31, czyli maksymalna głębokość. Większość systemów ma wiele tysięcy sprawdzeń jako limit, ale jeśli jesteś bardzo blisko tego, nadal może się to udać.
Peter Lawrey

9

Napisz funkcję użytkową, taką jak

public class ListUtil{

    public static int sum(List<Integer> list){
      if(list==null || list.size()<1)
        return 0;

      int sum = 0;
      for(Integer i: list)
        sum = sum+i;

      return sum;
    }
}

Następnie użyj like

int sum = ListUtil.sum(yourArrayList)

ale jak mogę to zrobić dla długiej wartości w arraylist?
Ravi Parmar

5

dla mnie najjaśniejszy sposób jest taki:

doubleList.stream().reduce((a,b)->a+b).get();

lub

doubleList.parallelStream().reduce((a,b)->a+b).get();

Wykorzystuje również wewnętrzne pętle, ale bez pętli nie jest to możliwe.


2

Możesz użyć API apache commons-collections.

class AggregateClosure implements org.apache.commons.collections.Closure {
        int total = 0;

        @Override
        public void execute(Object input) {
            if (input != null) {
                total += (Integer) input;
            }
        }

        public int getTotal() {
            return total;
        }
    }

Następnie użyj tego zamknięcia, jak pokazano poniżej:

public int aggregate(List<Integer> aList) {
        AggregateClosure closure = new AggregateClosure();
        org.apache.commons.collections.CollectionUtils.forAllDo(aList, closure);
        return closure.getTotal();
}

1

Jeśli znasz funkcję map, wiesz, że mapa może być również pętlą rekurencyjną lub pętlą rekurencyjną. Ale oczywiście musisz dotrzeć do każdego elementu. więc nie mogłem opracować Java 8, ponieważ niektóre składni nie pasują, ale chciałem być bardzo krótki, więc oto, co otrzymałem.

int sum = 0
for (Integer e : myList) sum += e;

Masz rację. Powiedziałem, że jest to minimalna pętla zamiast mapy, która może być rekurencyjna.
sivi

„Czy istnieje możliwość sumowania ArrayList bez zapętlenia”
aleksander

0

Biorąc pod uwagę, że lista może zawierać dowolne typy obiektów, nie ma wbudowanej metody, która pozwala zsumować wszystkie elementy. Możesz zrobić coś takiego:

int sum = 0;

for( Integer i : ( ArrayList<Integer> )tt ) {
  sum += i;
}

Alternatywnie możesz utworzyć własny typ kontenera, który dziedziczy po ArrayList, ale także implementuje metodę o nazwie sum (), która implementuje powyższy kod.


0

ArrayList to zbiór elementów (w formie listy), prymitywne są przechowywane jako obiekty klasy wrapper, ale jednocześnie mogę przechowywać również obiekty klasy String. SUM nie będzie miał w tym sensu. A tak przy okazji, dlaczego tak się boisz używać pętli for (ulepszonej lub przez iterator)?


0

Lub przełącz się na Groovy, ma funkcję sum () w kolekcji. [1,2,3,4,5,6]. Suma ()

http://groovy.codehaus.org/JN1015-Collections

Działa na tej samej maszynie JVM, co Twoje klasy Java.


8
Tak. Funkcja sum jest zdecydowanie powodem, aby przejść na inny język. : D
ruX

1
Pytanie jest otagowane Java, więc nie jest to technicznie poprawna odpowiedź.
Bengt

0

Ten link pokazuje trzy różne sposoby sumowania w Javie. Jest jedna opcja, której nie ma w poprzednich odpowiedziach przy użyciu Apache Commons Math.

Przykład:

public static void main(String args []){
    List<Double> NUMBERS_FOR_SUM = new ArrayList<Double>(){
         {
            add(5D);
            add(3.2D);
            add(7D);
         }
    };
    double[] arrayToSume = ArrayUtils.toPrimitive(NUMBERS_FOR_SUM
            .toArray(new Double[NUMBERS_FOR_SUM.size()]));    
    System.out.println(StatUtils.sum(arrayToSume));

}

Zobacz StatUtils api


0

Możesz użyć biblioteki GNU Trove :

TIntList tt = new TIntArrayList();
tt.add(1);
tt.add(2);
tt.add(3);
int sum = tt.sum();

0

Można to zrobić za pomocą metody Redukcja przy użyciu odwołań do metod reduce(Integer::sum):

Integer reduceSum = Arrays.asList(1, 3, 4, 6, 4)
        .stream()
        .reduce(Integer::sum)
        .get();

Lub bez Optional:

Integer reduceSum = Arrays.asList(1, 3, 4, 6, 4)
        .stream()
        .reduce(0, Integer::sum);
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.