มีความเป็นไปได้ที่ผลรวมของ ArrayList โดยไม่ต้องวนซ้ำ


88

มีความเป็นไปได้ของผลรวมArrayListโดยไม่ต้องวนซ้ำหรือไม่?

PHP ให้sum(array)ซึ่งจะให้ผลรวมของอาร์เรย์

โค้ด PHP ก็เช่น

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

ฉันต้องการทำสิ่งเดียวกันใน Java:

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

2
จะเกิดอะไรขึ้นถ้าArrayListไม่มีสิ่งที่ "สรุปได้"? ArrayList และอาร์เรย์ไม่จำเป็นต้องเป็นสิ่งเดียวกัน สำหรับการรวมตัวเลขในอาร์เรย์นั้นง่ายมากสำหรับการวนซ้ำองค์ประกอบและคำนวณผลรวมสะสม
— posdef

ฟังก์ชั่น PHP array_sumยังทำการวนซ้ำภายในเพียงแค่ซ่อนมันจากผู้ใช้
— Paŭlo Ebermann

1
เป็นคำถามที่สมเหตุสมผล ท้ายที่สุดการเขียนลูปเพื่อค้นหาองค์ประกอบที่ใหญ่ที่สุดในรายการก็เกือบจะเป็นเรื่องเล็กน้อย แต่ java.util.Collections มีวิธี max ()
— John Velonis

1
คำถามที่สมเหตุสมผลมากท้ายที่สุดนั่นคือประเด็นของวิธีการใช่มั้ย? Reuse :)
— Ben Taliadoros

ลูปมีความสวยงาม
— Alex78191

คำตอบ:


156

ครั้งเดียว หมด (มีนาคม 2014) คุณจะสามารถใช้สตรีม :

หากคุณมีไฟล์ List<Integer>

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

ถ้าเป็นไฟล์ int[]

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

5
mapใช้ลูปโดยปริยาย
— Nikos M.

8
คุณสามารถใช้การเรียกซ้ำเพื่อไม่ใช้การวนซ้ำ : D (อย่าทำแบบนี้)
— Caleb Fenton

23

จากนั้นเขียนเอง:

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

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

     return sum;
}

1
หรือขยาย ArrayList ด้วยวิธี sum เพื่อให้คุณสร้าง ArrayList ของคุณเอง
— Bueller

3
intเมื่อทำนอกจากนี้ที่จริงมันเป็นเพียงแค่ดีกว่าที่จะใช้ที่เรียบง่าย มีค่าเพียงเล็กน้อยในการใช้Integerกับคุณสมบัติการชกมวยอัตโนมัติของ java ที่นี่ นอกจากนี้คุณกำลังสร้างและสร้างIntegerวัตถุใหม่ที่อาจเกิดขึ้นใหม่ทุกครั้งเนื่องจากเป็นImmutableประเภท
— Java Drinker

10

ทางเลือกเดียวในการใช้การวนซ้ำคือการใช้การเรียกซ้ำ

คุณสามารถกำหนดวิธีการเช่น

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

สิ่งนี้ไม่มีประสิทธิภาพมากเมื่อเทียบกับการใช้ลูปธรรมดาและอาจระเบิดได้หากคุณมีองค์ประกอบมากมายในรายการ

อีกทางเลือกหนึ่งที่หลีกเลี่ยงไม่ให้สแตกล้นคือการใช้

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

สิ่งนี้ไม่มีประสิทธิภาพพอ ๆ กัน แต่จะหลีกเลี่ยงไม่ให้สแตกล้น


วิธีที่สั้นที่สุดในการเขียนสิ่งเดียวกันคือ

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

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

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

พิมพ์

sum(a) = 20

ในรหัสคุณพลาดการเรียกไป sum () ในคำจำกัดความแบบเรียกซ้ำครั้งแรก คำจำกัดความแบบวนซ้ำที่สองไม่ได้ป้องกันไม่ให้เกิดสแต็กล้นออกมาทำให้มีโอกาสน้อยลง
— Teudimundo

1
@Teudimundo True แม้ว่าจะไม่ได้ป้องกัน แต่ขนาดสูงสุดของ List คือ Integer.MAX_VALUE และ log2 คือ 31 ซึ่งเป็นความลึกสูงสุด ระบบส่วนใหญ่มีการโทรหลายพันครั้งเป็นขีด จำกัด แต่ถ้าคุณอยู่ใกล้กับสิ่งนี้มากก็ยังสามารถระเบิด
— Peter Lawrey

9

เขียนฟังก์ชัน util เช่น

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

จากนั้นใช้เช่น

int sum = ListUtil.sum(yourArrayList)

แต่ฉันจะทำมันให้เป็นค่ายาวใน arraylist ได้อย่างไร?
— Ravi Parmar

5

สำหรับฉันวิธีที่ชัดเจนที่สุดคือ:

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

หรือ

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

นอกจากนี้ยังใช้ลูปภายใน แต่เป็นไปไม่ได้หากไม่มีลูป


2

คุณสามารถใช้ apache commons-collections API

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

จากนั้นใช้การปิดนี้ตามที่แสดงด้านล่าง:

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

1

หากคุณรู้เกี่ยวกับฟังก์ชั่นแผนที่คุณจะรู้ว่าแผนที่สามารถวนซ้ำหรือวนซ้ำได้เช่นกัน แต่แน่นอนว่าคุณต้องเข้าถึงแต่ละองค์ประกอบให้ได้ ดังนั้นฉันไม่สามารถหา Java 8 ได้เนื่องจากไวยากรณ์บางอย่างไม่ตรงกัน แต่ต้องการสั้นมากดังนั้นนี่คือสิ่งที่ฉันได้รับ

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

คุณพูดถูก ฉันบอกว่ามันเป็นการวนซ้ำน้อยที่สุดแทนที่จะเป็นแผนที่ซึ่งสามารถวนซ้ำได้
— sivi

"มีความเป็นไปได้ที่จะมีผลรวมของ ArrayList โดยไม่ต้องวนซ้ำ"
— alexander

0

เนื่องจากรายการสามารถเก็บวัตถุประเภทใดก็ได้จึงไม่มีวิธีการในตัวที่ช่วยให้คุณสามารถรวมองค์ประกอบทั้งหมดได้ คุณสามารถทำสิ่งนี้:

int sum = 0;

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

หรือคุณสามารถสร้างประเภทคอนเทนเนอร์ของคุณเองซึ่งสืบทอดมาจาก ArrayList แต่ยังใช้เมธอดที่เรียกว่า sum () ซึ่งใช้โค้ดด้านบน


0

ArrayList เป็นชุดขององค์ประกอบ (ในรูปแบบของรายการ) แบบดั้งเดิมจะถูกเก็บไว้เป็นวัตถุคลาส Wrapper แต่ในเวลาเดียวกันฉันสามารถจัดเก็บวัตถุของคลาส String ได้เช่นกัน SUM จะไม่สมเหตุสมผลในเรื่องนั้น BTW ทำไมจึงกลัวที่จะใช้สำหรับลูป (ปรับปรุงหรือผ่านตัววนซ้ำ) ต่อไป?


0

หรือเปลี่ยนไปใช้ Groovy ก็มีฟังก์ชัน sum () ในคอลเล็กชัน [1,2,3,4,5,6] .sum ()

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

รันบน JVM เดียวกันกับคลาส java ของคุณ


8
ใช่. ฟังก์ชัน Sum เป็นเหตุผลที่แน่นอนในการเปลี่ยนไปใช้ภาษาอื่น : D
— ruX

1
คำถามถูกแท็กJavaดังนั้นนี่ไม่ใช่คำตอบที่ถูกต้องในทางเทคนิค
— Bengt

0

ลิงค์นี้แสดงวิธีการรวมใน java สามวิธีที่แตกต่างกันมีตัวเลือกหนึ่งที่ไม่ได้อยู่ในคำตอบก่อนหน้าโดยใช้ Apache Commons Math ..

ตัวอย่าง:

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

}

โปรดดูที่StatUtils api



0

สามารถทำได้ด้วยการลดโดยใช้การอ้างอิงวิธีการreduce(Integer::sum):

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

หรือไม่มีOptional:

Integer reduceSum = Arrays.asList(1, 3, 4, 6, 4)
        .stream()
        .reduce(0, Integer::sum);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.