Có khả năng tổng của ArrayList mà không lặp lại


87

Có khả năng tổng của ArrayListmà không lặp lại?

PHP cung cấp sum(array)sẽ cung cấp tổng của mảng.

Mã PHP giống như

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

Tôi cũng muốn làm điều tương tự trong Java:

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

2
Điều gì xảy ra nếu ArrayListkhông chứa một cái gì đó là "có thể tổng hợp"? ArrayList và một mảng không nhất thiết phải giống nhau. Đối với tính tổng các số trong một mảng, đó là một vòng lặp for rất đơn giản qua các phần tử và tính tổng tích lũy.
posdef

Hàm PHP array_sumcũng thực hiện một vòng lặp bên trong, nó chỉ ẩn nó khỏi người dùng.
Paŭlo Ebermann

1
Đó là một câu hỏi hợp lý. Xét cho cùng, việc viết một vòng lặp để tìm phần tử lớn nhất trong danh sách gần như là chuyện nhỏ, nhưng java.util.Collections cung cấp một phương thức max ().
John Velonis

1
Câu hỏi rất hợp lý, sau tất cả, đó là điểm của các phương pháp, phải không? Tái sử dụng :)
Ben Taliadoros

Vòng lặp là đẹp.
Alex78191 27/09/18

Câu trả lời:


154

Một lần hết (tháng 3 năm 2014), bạn sẽ có thể sử dụng các luồng :

Nếu bạn có một List<Integer>

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

Nếu đó là một int[]

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

5
mapsử dụng các vòng lặp một cách ngầm định
Nikos M.

7
Bạn có thể sử dụng đệ quy để không sử dụng vòng lặp. : D (đừng làm điều này)
Caleb Fenton

23

Sau đó tự viết:

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

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

     return sum;
}

1
Hoặc mở rộng ArrayList với phương thức sum để bạn có nó được tích hợp vào ArrayList của riêng bạn.
Bueller

3
Khi thực hiện việc bổ sung thực tế, chỉ cần sử dụng một đơn giản sẽ đẹp hơn int. Có rất ít giá trị khi sử dụng Integervới các tính năng tự động đấm bốc của java ở đây. Ngoài ra, bạn đang tạo và tạo lại nhiều Integerđối tượng tiềm năng mới mỗi lần, vì nó là một Immutablekiểu.
Java Drinker

10

Cách thay thế duy nhất để sử dụng vòng lặp là sử dụng đệ quy.

Bạn có thể xác định một phương pháp như

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

Điều này rất kém hiệu quả so với việc sử dụng một vòng lặp đơn giản và có thể bị nổ nếu bạn có nhiều phần tử trong danh sách.

Một giải pháp thay thế tránh tràn ngăn xếp là sử dụng.

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

Điều này cũng không hiệu quả, nhưng sẽ tránh được tràn ngăn xếp.


Cách ngắn nhất để viết những điều tương tự là

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

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

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

bản in

sum(a) = 20

Trong đoạn mã, bạn bỏ lỡ lệnh gọi đến sum () trong định nghĩa đệ quy đầu tiên. Định nghĩa đệ quy thứ hai không ngăn chặn việc tràn ngăn xếp xảy ra, nó ít xảy ra hơn.
Teudimundo

1
@Teudimundo Đúng, Mặc dù nó không ngăn cản điều đó, nhưng kích thước tối đa của Danh sách là Integer.MAX_VALUE và log2 là 31, là độ sâu tối đa. Hầu hết các hệ thống có hàng nghìn cuộc gọi là một giới hạn nhưng nếu bạn đang ở rất gần mức này, nó vẫn có thể bị nổ.
Peter Lawrey

9

Viết một hàm sử dụng như

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

Sau đó sử dụng như

int sum = ListUtil.sum(yourArrayList)

nhưng làm thế nào tôi có thể làm điều đó cho giá trị dài trong danh sách mảng?
Ravi Parmar

5

đối với tôi cách rõ ràng nhất là:

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

hoặc là

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

Nó cũng sử dụng vòng lặp bên trong, nhưng không thể không có vòng lặp.


2

Bạn có thể sử dụng API commons-collection của apache.

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

Sau đó sử dụng cách đóng này như hình dưới đây:

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

1

Nếu bạn biết về hàm bản đồ, thì bạn biết rằng bản đồ cũng có thể là vòng lặp đệ quy hoặc vòng lặp đệ quy. Nhưng rõ ràng bạn phải đạt được từng yếu tố cho điều đó. vì vậy, tôi không thể tìm ra Java 8, vì một số cú pháp không khớp nhưng lại muốn có một đoạn ngắn nên đây là những gì tôi nhận được.

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

Bạn đúng rồi. Tôi đã nói đó là một vòng lặp tối thiểu thay vì bản đồ có thể đệ quy đuôi.
sivi

"Có khả năng tổng của ArrayList mà không lặp lại"
alexander

0

Cho rằng một danh sách có thể chứa bất kỳ loại đối tượng nào, không có phương thức tích hợp nào cho phép bạn tính tổng tất cả các phần tử. Bạn có thể làm điều gì đó như sau:

int sum = 0;

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

Ngoài ra, bạn có thể tạo loại vùng chứa của riêng mình kế thừa từ ArrayList nhưng cũng thực hiện một phương thức gọi là sum () để triển khai mã ở trên.


0

ArrayList là một Tập hợp các phần tử (ở dạng danh sách), nguyên thủy được lưu trữ dưới dạng đối tượng lớp wrapper nhưng đồng thời tôi cũng có thể lưu trữ các đối tượng của lớp String. SUM sẽ không có ý nghĩa trong điều đó. BTW tại sao rất ngại sử dụng vòng lặp for (nâng cao hoặc thông qua trình lặp)?


0

Hoặc chuyển sang Groovy, nó có hàm sum () trên một tập hợp. [1,2,3,4,5,6] .sum ()

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

Chạy trên cùng một JVM như các lớp java của bạn.


8
Vâng. Hàm Sum chắc chắn là lý do để chuyển sang ngôn ngữ khác. : D
ruX

1
Câu hỏi được gắn thẻ Java, vì vậy về mặt kỹ thuật đây không phải là câu trả lời hợp lệ.
Kéo dài

0

Liên kết này hiển thị ba cách khác nhau để tính tổng trong java, có một tùy chọn không có trong các câu trả lời trước đó là sử dụng Apache Commons Math ..

Thí dụ:

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));

}

Xem api StatUtils


0

Bạn có thể sử dụng thư viện GNU Trove :

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

0

Điều này có thể được thực hiện bằng cách sử dụng các tham chiếu phương thức reduce(Integer::sum):

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

Hoặc không có Optional:

Integer reduceSum = Arrays.asList(1, 3, 4, 6, 4)
        .stream()
        .reduce(0, Integer::sum);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.