2

Say we have a list of a list of integers. What that would look like is [list1, list2, list3], basically List<List>. Then assume we have the master list masterList which is just List. Is there a way to check each list in List<List> and for each value in each list, if the value, or item, is in the master list, then leave as is, but if it is not in the master list then there should be a "(N/A)" next to it. So example:

List<Integer> masterList = Arrays.asList(122, 123, 124, 155, 621, 982);
List<Integer> list1 = Arrays.asList(122, 124, 155, 331, 982);
List<Integer> list2 = Arrays.asList(122, 124, 444);
List<Integer> list3 = Arrays.asList(2, 122, 123, 124, 133, 155, 332, 621, 667, 982);

// I guess each list could be on its own, but for my purposes the lists are in a list, so:

List<List<Integer>> lists = new ArrayList<>();
lists.add(list1);
lists.add(list2);
lists.add(list3);

So if we were to compare each list in lists to the masterList, then the end result should be a list of lists but each list will have updated values indicating if they are in the master list or not, so for pseudo-code ease sakes:

list1 = [122, 124, 155, 331(#N/A), 982(#N/A)]
list2 = [122, 124, 444(#N/A)]
list3 = [2(#N/A), 122, 123, 124, 133(#N/A), 155, 332(#N/A), 621(#N/A), 667(#N/A), 982(#N/A)]

and then I guess they would all be in lists again, so, lists.add(list1, list2, list3).

I tried coding this but failed, and some solutions i tried coming up with had really bad time/space complexity. It's assumed that every list involved is sorted, unique, and does not have to be the same size.

It is necessary that the original list is of Integer type so it could be sorted, but I know that in the end there needs to be a new list holding 3 new lists that in the end are of String type, not Integer type anymore. This is sort of like comparing 3 columns to 1 column using VLOOKUP in Excel. If anyone could help out with a solution, you have my blessings!! Thank you!

IHaveAQuestion
  • 143
  • 2
  • 12
  • I would suggest you replace your `List` with `Set`, which guarantee unicity and, for `SortedSet` implementation, total ordering. The `java.util.Collection`subinterfaces are powerful enough, take the time to read their Javadoc, it's really well done. – Riduidel Sep 29 '20 at 06:34
  • The contains() method in java.util.List is a good starting point to check if a list contains an element. https://docs.oracle.com/javase/8/docs/api/java/util/List.html#contains-java.lang.Object- – Shankar Sep 29 '20 at 06:43
  • Rather you can use List of a pair as a result and sort by only Integer part only. – Eklavya Sep 29 '20 at 06:43

2 Answers2

2

Solution

Simply use Stream::map for each number present in the list. Using the ternary operator, you transform it either to self or to a new String value with (#N/A) prefix. Note the newly returned structure is List<List<String>> as long as 331(#N/A) us not an integer value.

List<List<String>> checkedList = lists.stream()
        .map(list -> list.stream()
                         .map(i-> masterList.contains(i) ? i + "" : i + "(#N/A)")
                         .collect(Collectors.toList()))
        .collect(Collectors.toList());

checkedList.forEach(System.out::println);               // results in the output below
[122, 124, 155, 331(#N/A), 982]
[122, 124, 444(#N/A)]
[2(#N/A), 122, 123, 124, 133(#N/A), 155, 332(#N/A), 621, 667(#N/A), 982]

Suggestion

However, the result is a bit questionable and you lose comfortable handling with numbers and the data look quite dirty. I'd rather split the lists into two by the element's presence in the masterList. Use Collectors.partitioningBy:

List<Map<Boolean, List<Integer>>> map = lists.stream()
       .map(list -> list.stream()
                        .collect(Collectors.partitioningBy(masterList::contains)))
       .collect(Collectors.toList());

map.forEach(System.out::println);                       // results in the output below
{false=[331], true=[122, 124, 155, 982]}
{false=[444], true=[122, 124]}
{false=[2, 133, 332, 667], true=[122, 123, 124, 155, 621, 982]}

The false indicates these not present in masterList. The true represents otherwise. Feel free to check it out at JDoodle.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • Oh that second suggestion looks wonderful, thank you so much. Would you mind pasting the full code you used to achieve that result, so I can paste that in my editor and play around with it? I've never seen that partitioningBy before – IHaveAQuestion Sep 29 '20 at 13:26
  • Actually, it is a full solution, just copy+paste it after your initializing snippet. I attach JDoodle to my answer. Btw. `partitioningBy(Predicate)` works the same like `groupingBy(Function)` where the maping function returns `Boolean` (the map key). Since List's `contains(E)` method returns `boolean` the `partitioningBy` is prefferred. – Nikolas Charalambidis Sep 29 '20 at 13:39
  • Amazing, thank you so much. Out of curiosity, i'm not sure if I've seen this before, but is there a way to display the results (for both your methods) in a tabular form, or a nicer to view form? – IHaveAQuestion Sep 29 '20 at 13:45
  • You're welcome. To answer you displaying in a tabular form, feel free to ask a new question.However, start with skimming through the existing question https://stackoverflow.com/questions/2745206/output-in-a-table-format-in-javas-system-out or check out for some open-source libraries in case of more complicated output. – Nikolas Charalambidis Sep 29 '20 at 15:27
  • Thank you, I did have one further small question about the way you did the partition. If I were to have a bigger set of data, it would be very long and it would obviously be hard to find where the "true" is. Is there a way to have it show something on 2 lines, like: {false = [331] true = [122, 124, 155, 982]} something like that? – IHaveAQuestion Sep 29 '20 at 21:06
  • Something like https://www.jdoodle.com/iembed/v0/1No is possible. You have to try by yourself or ask another question if no success after at least few tries. – Nikolas Charalambidis Sep 29 '20 at 21:30
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222294/discussion-between-nikolas-and-ihaveaquestion). – Nikolas Charalambidis Sep 30 '20 at 08:27
  • May I ask you another variance of this that I just thought of? – IHaveAQuestion Oct 21 '20 at 04:52
  • Please checkout this post I just made as well! https://stackoverflow.com/questions/64457200/java-method-to-check-if-integers-in-list-are-contained-in-another-list-of-a-list – IHaveAQuestion Oct 21 '20 at 05:28
1

You can use List of Integer, Boolean pair per list then you can sort the list by Integer part of pair. For pairing you can use AbstractMap.SimpleEntry.

List<List<AbstractMap.SimpleEntry<Integer, Boolean>>> res = 
   lists.stream()
        .map(e -> e.stream()
                   .map(ee -> new AbstractMap.SimpleEntry<>(ee, masterList.contains(ee)))
                   .collect(Collectors.toList()))
        .collect(Collectors.toList());

Here, transform every Integer into AbstractMap.SimpleEntry<Integer, Boolean> by checking every element of list exists in masterList using contains() method

I guess (N/A) view part only, if you want directly store String for element you can use AbstractMap.SimpleEntry<Integer, String> also and map as

ee -> new AbstractMap.SimpleEntry<>(ee, masterList.contains(ee)? "(N/A)" : null)

And to sort a List<AbstractMap.SimpleEntry<Integer, Boolean>> by it's Integer part only.

Collections.sort(list, Comparator.comparing(e -> e.getKey()));
Eklavya
  • 17,618
  • 4
  • 28
  • 57