1

I am trying to collect a list into a map but I have duplicate entry in the list object.

So suppose I have aList where in that I have

[{1, "abc.jpg"}, {2, "bcd.png"}, {1, "mno.jpg"}, {3, "abc.jpg"}, {1, null}, {1, ""}]

Now in above list you can see 1 has value at repetition with different values.

I want to collect the above list into map provided only if it has some value in it.

like in above set you may have question if I find distinct then collect by grouping them which filled value will be picked my answer is any filled value is required but not empty, whitespace or null.

so anyone could be okay except in three case empty, whitespace or null.

I just want to set in my list if that id has any image or not therefore checking for only empty, whitespace or null.

Output(Ambiguous):

Output 1

[{1, "abc.jpg"}, {2, "bcd.png"}, {3, "abc.jpg"}]

Output 2

[{2, "bcd.png"}, {1, "mno.jpg"}, {3, "abc.jpg"}]

Both above list result could be the output in map.

My Approach:

    itemImageMap = imageService.findByItemUuidIn(itemUuids)
   .stream().filter(obj->(Objects.nonNull(obj)&& Objects.nonNull(obj[1])))
   .collect(Collectors.toMap(obj->String.valueOf(obj[0]), obj->String.valueOf(obj[1])));

I am getting duplicate key error.

For more clarity on what my purpose is to collect this in map. Once I collect into map my goal is this =>

itemDetailsList.stream().filter(obj->itemImageMap.containsKey(obj.getItemUuid())).map(obj-> {
            
                String imageUrl = itemImageMap.get(obj.getItemUuid());
                
                if(StringUtils.isNotBlank(imageUrl))
                    obj.setShowImage(true);
                
                return obj;
            });

if I have a path then set true else default is false.

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
Kramer
  • 389
  • 8
  • 34
  • 2
    It would be so much easier to help you if instead of the long read you just provided an input (as you did) and an expected output. – Maksym Rudenko Nov 16 '20 at 12:04
  • @MaksymRudenko added expected result since output is ambiguous therefore both possible result presented – Kramer Nov 16 '20 at 12:10

4 Answers4

3

To get rid of the duplicate key error use the overloaded version of toMap with a third parameter indicating which value to keep in case of a duplicate. For example to keep the first value:

 .collect(Collectors.toMap(obj->String.valueOf(obj[0]), obj->String.valueOf(obj[1]), (first, second) -> first));

But in case of duplicates, instead of ignoring a value, you can also use your keys to group the values into a list to get a Map<String,List<String> instead of Map<String,String>. Something like:

.collect(Collectors.groupingBy(obj->String.valueOf(obj[0]), 
                                   Collectors.mapping(obj->String.valueOf(obj[1]), 
                                   Collectors.toList())));
Eritrean
  • 15,851
  • 3
  • 22
  • 28
2
var list = List.<Map.Entry<Integer, String>>of(
    new AbstractMap.SimpleImmutableEntry<>(1, "abc.jpg"),
    new AbstractMap.SimpleImmutableEntry<>(2, "bcd.png"),
    new AbstractMap.SimpleImmutableEntry<>(1, "mno.jpg"),
    new AbstractMap.SimpleImmutableEntry<>(3, "abc.jpg"),
    new AbstractMap.SimpleImmutableEntry<>(1, null),
    new AbstractMap.SimpleImmutableEntry<>(1, "")
);

var map = list.stream()
    .filter(it -> it.getValue() != null && !it.getValue().isEmpty())
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v1));

System.out.println(map);

{1=abc.jpg, 2=bcd.png, 3=abc.jpg}

I used Java 11 var and List.of, but the code could easily be adapted to Java 8. Java is so dang verbose, new AbstractMap.SimpleImmutableEntry<>(1, "abc.jpg") gives me headache every time I want to create a pair.

Abhijit Sarkar
  • 21,927
  • 20
  • 110
  • 219
1

Use Collectors.groupingBy using the getItemUuid() method with subsequent downstreams:

  • Collectors.mapping to get the image URL (I assume there is a method MyObject#getUrl).
  • Collectors.filtering to filter out the invalid Strings as of and later, otherwise you need to use filter before you enter the collect method.

Java 8

Map<Integer, List<String>> map = list.stream()
    .filter(obj -> obj.getUrl() != null && !obj.getUrl().trim().isEmpty())
    .collect(Collectors.groupingBy(
            MyObject::getItemUuid,
            Collectors.mapping(MyObject::getUrl, Collectors.toList())));

Java 9+

Map<Integer, List<String>> map = list.stream()
    .collect(Collectors.groupingBy(MyObject::getItemUuid,
            Collectors.mapping(MyObject::getUrl,
                    Collectors.filtering(url -> url != null && !url.trim().isEmpty(), 
                            Collectors.toList()))));

Result:

{1=[abc.jpg, mno.jpg], 2=[bcd.png], 3=[abc.jpg]}

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
0

If I got your idea correctly - here is my answer inspired by this answer:

class Data {
Integer id;
String name;

public Data(Integer id, String name) {
    this.id = id;
    this.name = name;
}

public Integer getId() {
    return id;
}

@Override
public String toString() {
    return "Data{" + "id=" + id + ", name='" + name + '\'' + '}';
}
}

public class Main {

public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
    Set<Object> seen = ConcurrentHashMap.newKeySet();
    return t -> seen.add(keyExtractor.apply(t));
}

public static void main(String[] args) {
    List<Data> list = List.of(new Data(1, "abc.jpg"), new Data(2, "bcd.png"), new Data(1, null));

    List<Data> result = list.stream()
                            .filter(d -> d.name != null && !d.name.equals(""))
                            .filter(distinctByKey(Data::getId))
                            .collect(Collectors.toList());

    result.forEach(System.out::println);
}

}

Maksym Rudenko
  • 706
  • 5
  • 16
  • will it work if I have duplicate in first case filter but it might give exception in second case maybe when It couldn't determine distinct key.....can you run with adding one more {1, "mno.jpg"} – Kramer Nov 16 '20 at 12:36
  • 1
    The JDK has a class for what you call `Data` - `Map.Entry`. – Abhijit Sarkar Nov 16 '20 at 12:41
  • @Kramer I tried with ` List list = List.of(new Data(1, "abc.jpg"), new Data(2, "bcd.png"), new Data(1, null), new Data(1, "mno.jpg"), new Data(1, "mno.jpg")); ` and it worked. Key is the "1", not the image `name`. – Maksym Rudenko Nov 16 '20 at 12:49
  • @AbhijitSarkar You don't have to use that class if you don't want to. The part that solves your problem is the `Predicate`. – Maksym Rudenko Nov 16 '20 at 12:50
  • I don't have a problem, OP does. – Abhijit Sarkar Nov 16 '20 at 12:51