Java sum list of integers

Sum of a list of integers using Java 8

«The sum value 2499950000 itself is within the range that can be expressed by an int as I understand.» No, the max value for an int is 2147483647 which is less than that.

Try running it without the call to System.out.println(list.parallelStream(). . This adds considerable time to your execution.

A parallel stream has sufficient overhead, and is worth it only for larger iteration times (per element duration), which then could be done in parallel. If you called Thread.sleep(100) the statistics would revert.

@DesertIvy The System.out.println is there in both cases, so it cannot matter. It also does not matter for the lambdas, as the print is definately the last thing being executed.

3 Answers 3

Here is my quick and dirty benchmark, allowing for JIT warm-up and GC-ing betwen each test. The results:

Note that I have modified your code to make the three tests as equivalent as possible — in particular, for lambdas, I’m using a reduction to add the BigIntegers instead of converting to long.
I have also removed the unnecessary creation of new BigInteger(«2») at each iteration.

public class Test1 < static Listlist = new LinkedList<>(); static BigInteger TWO = new BigInteger("2"); public static void main(String[] args) < createList(); long sum = 0; //warm-up for (int i = 0; i < 100; i++) < sum += forLoop().longValue(); sum += lambda().longValue(); sum += parallelLambda().longValue(); > < System.gc(); long start = System.currentTimeMillis(); for (int i = 0; i < 100; i++) sum += forLoop().longValue(); long end = System.currentTimeMillis(); System.out.println("Time taken using for loop: " + (end - start) + " ms"); > < System.gc(); long start = System.currentTimeMillis(); for (int i = 0; i < 100; i++) sum += lambda().longValue(); long end = System.currentTimeMillis(); System.out.println("Time taken using lambda: " + (end - start) + " ms"); > < System.gc(); long start = System.currentTimeMillis(); for (int i = 0; i < 100; i++) sum += parallelLambda().longValue(); long end = System.currentTimeMillis(); System.out.println("Time taken using parallelLambda: " + (end - start) + " ms"); >> private static void createList() < for (int i = 0; i < 100000; i++) < list.add(new BigInteger(String.valueOf(i))); >> private static BigInteger forLoop() < BigInteger sum = BigInteger.ZERO; for(BigInteger n : list) < if(n.mod(TWO).equals(BigInteger.ZERO)) sum = sum.add(n); >return sum; > private static BigInteger lambda() < return list.stream(). filter(n ->n.mod(TWO).equals(ZERO)). reduce(ZERO, BigInteger::add); > private static BigInteger parallelLambda() < return list.parallelStream(). filter(n ->n.mod(TWO).equals(ZERO)). reduce(ZERO, BigInteger::add); > > 

For your first question: Your value may have been greater than Integer.MAX_VALUE , and thus overflowing, which means it will be represented externally as starting at Integer.MIN_VALUE . Overflow is the keyword here.

Читайте также:  Creating lists in java

For the second part, I do not know exactly why it differs, probably can be found in the bytecode ultimately, but is this really an issue, or a case of premature optimization? If it is the first, then you should worry, if it’s the second case, then you should not pay attention to it being slower.

One difference I observe from your code though is that, with:

  • Java 6: You use one BigInteger sum , and call the .add() method on it.
  • Java 8: You use some long variable, and internally that variable gets added to.

Also, you are using a parallelStream() here for calculations that are very fast, this may lead to the issue that creating the new underlying threads actually costs more time than just using a normal linear stream() .

Moreover, if you are really measuring the speed, then you should do more tests than a single run per testcase, the timing can be dependant on other factors too — The JVM, your CPU’s clock speed, etc.

As last edit, your Java 8 code does actually not represent your Java 6 code, it should be:

final BigInteger sum = BigInteger.ZERO; list.stream() .filter(n -> n.mod(new BigInteger("2")).equals(BigInteger.ZERO)) .forEach(n -> < sum = sum.add(n); >); 

To fully represent your Java 6 code, be aware though that the introduction of sum is not really a good thing here, and this code will not work at all if you are using it for parallel computations.

One last edit, to correctly show how it should be done in Java 8, which looks correct, works for parallel versions and maybe even can pick up additional performance in linear versions:

 Optional sum = list.stream() .filter(n -> n.mod(new BigInteger("2")).equals(BigInteger.ZERO)) .reduce((n1, n2) -> n1.add(n2)); System.out.println(sum.get()); 

Here I am using the reduce() operator, which takes a BinaryOperator as argument, which I use to add the BigInteger s together.

One caveat is that it comes with the fact that the stream may be empty, so it does not know whether there is a value, so it returns an Optional .

Please carefully note that normally you need to call sum.isPresent() to check whether it actually has a value, but in this we know that there must be a value as !list.isEmpty() , and thus we proceed to call sum.get() directly.

Lastly, I have tested the different versions on my PC with 1 million numbers:

  • Java 6: Roughly 190 ~ 210ms.
  • Java 8 your code: Roughly 160 ~ 220ms.
  • Java 8, mine linear: Roughly 180 ~ 260ms.
  • Java 8, mine parallel: Roughly 180 ~ 270ms.

So, as this was not really proper microbenchmarking, I think the conclusion is that it does not really matter what you use for this kind of purposes.

Источник

Sum a List of numbers in Java

wordpress-sync/Java-engineering-feature

Every now and then, I need to do some basic stuff in Java and I wonder what is the best way to this. This happened to me a few days ago! I needed to simply get the sum of a List of numbers and I found out there are a number of ways — pun intended — to do this.

The old-fashioned approach

We can create a simple loop to do this. I am using Java 11 so, forgive me if you are using, for example, Java 8, and the List.of and var does not work in your case. Nonetheless, I believe you’ll still get the point.

var listOfNumbers = List.of(1,2,3,4,5,6,7,8,9,10); var sum = 0; for (int i = 0; i < listOfNumbers.size() ; i++)  sum += listOfNumbers.get(i); >

Obviously, since Java 5, we have enhancements for loops so, I can rewrite the same code like this.

var listOfNumbers = List.of(1,2,3,4,5,6,7,8,9,10); var sum = 0; for (int number : listOfNumbers)  sum += number; >

The difference is subtle. However, it is already more expressive as it says something like «of each number coming from listOfNumbers I want to do the following . «.

The Java Stream approach

People who know me, know that I was brainwashed, during my university days, with programming in Haskell. This means I have a lot of love for pure functional programming. Not that Java can handle that ?, but the expressiveness of functional programming is somewhat available using the stream API.

With the stream API in Java, we can execute the MapReduce programming model. For the issue I am trying to solve here, I do not need to map as the numbers will stay as they are. I do, however, have to reduce the List into a single number, the sum.

Collect

In probably 99% of the cases, we use the collect function with the standard toList() collector to reduce our stream back into a List.Similar to this:

 var time2ToList = listOfNumbers.stream() .map(i -> i * 2) .collect(Collectors.toList());

However, there is more to life than collecting a stream back into a List. Browsing the Collectors library you can find functions like summingInt() , summingDouble() and summingLong() .You can use these functions to collect (or reduce) the List into the sum.

The summmingInt function does require a function that turns the input you have into an int . In this case, I can simply use «identity function». The function i -> i will be sufficient.

 var listOfNumbers = List.of(1,2,3,4,5,6,7,8,9,10); var sum = listOfNumbers.stream() .collect(Collectors.summingInt(i -> i));

This identity function might look silly so, you can use Integer.intValue() instead.

 var listOfNumbers = List.of(1,2,3,4,5,6,7,8,9,10); var sum = listOfNumbers.stream() .collect(Collectors.summingInt(Integer::intValue));

When I do this, my IDE—IntelliJ IDEA in my case—advises me to refactor this and use the mapToInt() function like seen below:

 var listOfNumbers = List.of(1,2,3,4,5,6,7,8,9,10); var sum = listOfNumbers.stream() .mapToInt(Integer::intValue).sum();

Technically what we do here is mapping every item to an int, what it already is ¯\(ツ)/¯ right, and reduce it with the sum() function.

It gets more clear if you look at the inferred types. You simply cannot have a List of primitives. So, the List is a list of Integer (the Object). This means that every item in the list needs to get back to the primitive int to make the sum() possible. The previous example with the identity function in the collector works because of Java unboxing.

If you prefer using primitive Lists in Java, I suggest taking a look at the Eclipse Collections library.

Reduce

Reduction in Java is achieved by a couple of function in the stream API.In addition to collect() , there is also the obviously-named function reduce() .

 var listOfNumbers = List.of(1,2,3,4,5,6,7,8,9,10); var sum = listOfNumbers.stream() .reduce(0 , (num1, num2) -> num1 + num2);

The reduce function in this case takes a starting point and BiFunction lambda expression. The BiFunction is applied to the starting point and the first number,he result of the function is applied to the second number, and so on.

The code above does something like this:0 + 11 + 23 + 36 + 4etc …

Now, you can omit the starting point 0 . However, the reduce function will return an Optional in this case as the List it tries to reduce might be empty.

Conclusion

As you can see, there are multiple ways to solve this problem. Without any doubt, people will come up with even more exotic ways to solve this. My personal favorite is the reduce() option. For me, this is the most expressive and pure solution in Java. I simply want to reduce a list to a single number and don’t need to care of the transformations from boxed types to primitives. Furthermore, I can reuse this approach when I need to reduce a List of other types by writing a reduction lambda function that fits my needs.

Источник

Sum all the elements java arraylist

This Question should be re-opened. It is valid, specific, and useful. Look at the up-votes on both Questions and Answers. Look at the newer information being added about using Java Streams for a functional solution.

8 Answers 8

double sum = 0; for(int i = 0; i < m.size(); i++) sum += m.get(i); return sum; 
double sum = 0; for(Double d : m) sum += d; return sum; 

Why do you think it is?? Does it cause Performance Degradation?? Less and Clean Code, I was hoping for!

@AnandVarkeyPhilips The 😛 on the end of comment by Barranka means she/he was joking, or half-joking. See Emoticons list: Tongue sticking out, cheeky/playful, blowing a raspberry.

@AnandVarkeyPhilips I didn't mean to offend you in any way, nor I think your solution is incorrect. Your answer is correct, and I was merely joking (thanks to BasilBourque for pointing it out)

double sum = m.stream() .mapToDouble(a -> a) .sum(); System.out.println(sum); 

a -> a is a lambda function. Before the arrow is the parameter list (a) after the arrow is the body of the function (a). It's roughly equivalent to double identity(double a) < return a >

Java 8+ version for Integer , Long , Double and Float

 List ints = Arrays.asList(1, 2, 3, 4, 5); List longs = Arrays.asList(1L, 2L, 3L, 4L, 5L); List doubles = Arrays.asList(1.2d, 2.3d, 3.0d, 4.0d, 5.0d); List floats = Arrays.asList(1.3f, 2.2f, 3.0f, 4.0f, 5.0f); long intSum = ints.stream() .mapToLong(Integer::longValue) .sum(); long longSum = longs.stream() .mapToLong(Long::longValue) .sum(); double doublesSum = doubles.stream() .mapToDouble(Double::doubleValue) .sum(); double floatsSum = floats.stream() .mapToDouble(Float::doubleValue) .sum(); System.out.println(String.format( "Integers: %s, Longs: %s, Doubles: %s, Floats: %s", intSum, longSum, doublesSum, floatsSum)); 

I haven't tested it but it should work.

public double incassoMargherita() < double sum = 0; for(int i = 0; i < m.size(); i++) < sum = sum + m.get(i); >return sum; > 

Источник

Sum of List recursively

Hello fellow programmers. I am having a very silly problem.. I'm supposed to sum all the integers in a List, recursively. I know that there is an easier way to do this, and I actually made that method too (see class below). But the meaning of this assignment is that I have to split the list up into 2 halves and then calculate the sum recursively on both halves, and last I just return half1 + half2. The problem is that the advanced method does not return the sum of all values. Can anyone please help me? The method sum is the simple method. Summer(Summarize in danish) is the more advanced method.

package opgave1; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; public class BinærSøgning < public static void main(String[] args) < Random random = new Random(); int tal = 3; Listliste = new ArrayList(); for (int i = 0; i < 10; i++) liste.add(random.nextInt(10)); Collections.sort(liste); System.out.println(liste); // System.out.println(binærSøgning(liste, 0, tal)); System.out.println(summer(liste, 0)); >public static int binærSøgning(List liste, int start, int find) < if (liste.size() >0) < int midt = liste.size() / 2; if (liste.get(midt) == find) return start + midt; else if (liste.size() >1) < if (find < liste.get(midt)) return binærSøgning(liste.subList(0, midt), start, find); else return binærSøgning(liste.subList(midt + 1, liste.size()), start + midt + 1, find); >> return -1; > public static int sum (List list, int i) < if (i == list.size()) return 0; else return list.get(i) + sum(list, i+1); >public static int summer(List list, int start) < int right = 0; int left = 0; if(start == list.size())< return 0; >else < int mid = list.size() / 2; if(start < mid)< left += list.get(start) + summer(list.subList(0, mid), start+1); >else if(mid < list.size())< right += list.get(mid) + summer(list.subList(mid+1, list.size()), mid+1); >> return right + left; > > 

You should try to use a debugger, or simple print-statements to narrow down on the source of the error.

Do you have a problem when size of your list is a power of 2 (etc. 64), I think you lose some elements when you divide to 2

Источник

Оцените статью