Reputation: 43
So I have a an array List that looks like this: <id,value,id,value,...>
and I should find all the elements with the same id and add together there respected values into a result array list (value always comes after the id). At first I thought the problem was easy and went ahead and tried this:
List<String> resultList = new ArrayList<>();
for(int i = 0; i < myList.size(); i+=2){
BigInteger currentID = new BigInteger(myList.get(i));
BigInteger currentSum = new BigInteger(myList.get(i+1));
String currentId = myList.get(i);
int j = 2;
while(j < myList.size()){
if(currentId.equals(myList.get(j))){
BigInteger value2 = new BigInteger(myList.get(j+1));
currentSum = currentID.add(value2);
}
resultList.add(currentId);
resultList.add(String.valueOf(currentSum));
j+=2;
}
}
Needless to say it isn't correct, one of the many problems is that values which haven been already added together will be readded into the result array so I think they should be removed somehow in the loop. Do you guys have any suggestions how to go around this?
Upvotes: 4
Views: 2709
Reputation: 718788
It is easiest to do this using a Map
. But it can also be done without changing the input data structure, or using any intermediate data structure.
Here is an untested code sample. I have simplified the problem by using List<Integer>
List<Integer> myList = ...
List<Integer> resultList = new ArrayList<>();
for (int i = 0; i < myList.size(); i += 2) {
int id = myList.get(i);
// Check that we haven't accumulated this id already
boolean seen = false;
for (int j = 0; j < i && !seen; j += 2) {
seen = myList.get(j) == id;
}
if (seen) {
continue;
}
// Accumulate values for 'id'
int sum = myList.get(i + 1);
for (int j = i + 2; j < myList.size(); j += 2) {
if (myList.get(j) == id) {
sum += myList.get(j + 1);
}
}
// Send to output ...
resultList.add(id);
resultList.add(sum);
}
This solution is O(N^2)
. And since you are actually using String
and BigInteger
rather than Integer
, that makes it even more expensive.
A solution using a Map
should be O(NlogN)
or O(N)
depending on the map type.
Aside: It would be faster in some cases if you used resultList
rather than myList
in the first inner loop. But the way I did it above is more obvious ...
Upvotes: 1
Reputation: 40034
If you want to use streams you can do it like this.
Given a list like the following:
List<BigInteger> list = List.of(1,10,3,20,3,40,1,5,4,7,1,8,4,9,6,20)
.stream().mapToLong(a -> a).mapToObj(
BigInteger::valueOf).collect(Collectors.toList());
First accumulate the sums in a map with the key
being the id.
Map<BigInteger, BigInteger> mapfinal =
IntStream.iterate(0, i -> i < list.size(), i -> i += 2).mapToObj(
i -> new BigInteger[] { list.get(i), list.get(i + 1)
}).collect(Collectors.groupingBy(i -> i[0],
Collectors.reducing(BigInteger.ZERO,
a -> a[1],
(a, b) -> a.add(b))));
You can stop there and just use the map, or you can convert it to a list like the one you started with of alternating id/value
pairs.
List<BigInteger> listfinal = mapfinal
.entrySet()
.stream()
.flatMap(e -> Stream.of(e.getKey(), e.getValue()))
.collect(Collectors.toList());
And print the list.
System.out.println(listfinal);
[1, 23, 3, 60, 4, 16, 6, 20]
Upvotes: 2
Reputation: 119
Assuming you can use a Map:
My initial thought it to use a Map<String, String> map = new HashMap();
Pseudo code:
For each (id,value pair) in resultList
if map.get(id) exists
add the value to the existing entry in the map
else
add a new entry in the map for (id,value)
As code (NOTE: untested and might not compile, wouldn't copy & paste directly):
Map<String, String> map = new HashMap<>();
for(int i = 0; i < myList.size(); i+=2){
String listId = resultList.get(i); //get the Id from the resultList
String listValue = resultList.get(i+1) //get the value from the resultList
if(map.get(listId) != null) { // if the map has this Id
map.put(listId, map.get(listId)+ listValue); // add the Id's list value
}
else { // if the map doesn't have this Id
map.put(listId, listValue) // add the entry to the map
}
}
You can then take the resulting map
and transform is back into a list.
I'll let you write the code to take each entry in the map and add it to a new List. Google can be helpful here.
Upvotes: 4