Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign incremental-value to the list in java 8

Tags:

java

java-8

You assume that there are a list of an object. The list is sorted by one or more field of that object. So according to sorted list, i want to set a field of that object with incremental-value.
For clarifying, pay attention to the below example:

public class ObjectTest {
   int id;
   int userId;
   int code;
}

As above ObjectTest, any user has its own code.
There are a list of ObjectTest.

List<ObjectTest> objTests;

It is sorted:

objTests.sort(Comparator.comparing(DataSet::getUserId).thenComparing(DataSet::getCode));

So after sorting by userId and code, i want to set value from 1 to where any user has the its own code. The incremental value again is resetted to 1 when userId is changed.

If there are the following collection of ObjectTest.

    id     userId    code
--------------------------------
             100     5
             200     6
             100     7
             200     9
             200     10
             100     2

After the above scenario that is explained, the following collection will be:

id      userId     code
1        100        2
2        100        5
3        100        7
1        200        6
2        200        9
3        200        10

Is it possible with lambda expression in java

like image 392
reza ramezani matin Avatar asked Jun 04 '18 11:06

reza ramezani matin


People also ask

How do you increase a value by 1 in Java?

Increment Operator (++) The increment (++) operator (also known as increment unary operator) in Java is used to increase the value of a variable by 1. Since it is a type of a unary operator, it can be used with a single operand.

How to increment a value for a particular key in HashMap?

6.2 The below example uses computeIfAbsent to provide a default value for the key; computeIfPresent to update or increase the key value. 6.3 There is also a putIfAbsent to update the value only if the key doesn't exist. Map<String, Integer> map = new HashMap<>(); for (int i = 0; i < 10; i++) { //map.


3 Answers

Something along the lines of this should work:

List<ObjectTest> resultSet = 
objTests.stream()
        .sorted(Comparator.comparing(ObjectTest::getUserId).thenComparing(ObjectTest::getCode))
        .collect(Collectors.groupingBy(ObjectTest::getUserId, LinkedHashMap::new, Collectors.toList()))
        .values()
        .stream()
        .map(e -> {
            IntStream.range(0, e.size())
                    .forEach(i -> e.get(i).setId(i + 1));
            return e;
        })
        .flatMap(Collection::stream)
        .collect(Collectors.toList());

Note, I have not compiled this code.

like image 195
Ousmane D. Avatar answered Oct 20 '22 18:10

Ousmane D.


You can create a map of userId to a scoped atomic integer object, then iterate over the sorted list to set the ID.

Map<Integer, AtomicInteger> userIds = 
        objTests.stream()
        .map(obj -> Integer.valueOf(obj.getUserId()))
        .distinct()
        .collect(Collectors.toMap(Function.identity(), 
                 (id) -> new AtomicInteger(1)));

The above map contains an atomic integer object for each unique userId.

objTests.stream()
        .forEach(obj -> obj.setId(userIds.get(obj.getUserId())
                                   .getAndIncrement()));

This last code just iterates over the sorted list, then assigns an id read from the atomic integer associated with the user ID on the instance.

like image 43
ernest_k Avatar answered Oct 20 '22 18:10

ernest_k


It may be possible but you should most likely not solve it with the streams API.

The reason is that the streams API ist Javas implementation of functional programming and one of the key assumptions in FP is that objects (or better any data) have no relationship to each other and no function changes the state of the Input data.

Therefore your requirement breakes with FPs key assumption.

What is your idea to get my goal? – reza ramezani matin

Group objects by user ID:

Map<Integer,ObjectTest> userIdMap= objTests.stream()
    .collect(Collectors.groupingBy(
                           ot ->ot.userId , ot ->ot
                    ));

enumerate with legacy Looping:

for(Collection<ObjectTest> ol : userIdMap.values()){
   objectList = new ArrayList(ol);
   Colections.sort(ol, /* comparator here*/);
   for(int id = 0; id < ol.size();)
      objectList.get(id).id=++id;
}
like image 1
Timothy Truckle Avatar answered Oct 20 '22 17:10

Timothy Truckle