1

I'm studying for Java 8 Lambda and Unary Functional Interface. I have a practice assignment about "Function" class using HashMap, which the following steps to do:

  1. Create a variable of type Function<Set, Map> that receives a Set and creates a HashMap using lambda expressions

  2. Put words in the map, using as key the uppercase first letter of that word

  3. Execute lambda expression and view the result

I trying in the following way, but it doesn't work. I think that the problem is in the lambda expression, but I want to understand how I have to do (for simplicity I put the same word as key). In this way, the result is "null".

import java.util.*;
import java.util.function.Function;

public class FunctionTest {

public static void main(String[] args) {
        HashSet<String> hs = new HashSet<String>();
        hs.add("ciao");
        hs.add("hello");
        hs.add("hallo");
        hs.add("bonjour");

        Function<Set, Map> setToMap = s2 -> (Map) new HashMap().put(s2,s2);

        System.out.println(setToMap.apply(hs));
   }
}

For the above example, the expected result should be {B=bonjour, C=ciao, H=hello}.

Giacomo Brunetta
  • 1,409
  • 3
  • 18
  • 38
  • So what exactly is the result you want? A `Map` from `Character` to `String`? – jbx May 17 '18 at 15:27
  • I want to use the Unary function "Function" in order to pick a Set and create an HashMap in which are stored words of the Set – Giacomo Brunetta May 17 '18 at 15:28
  • @Aaron I wrote "(for semplicity I put the same word as key)". The result is simply "null" – Giacomo Brunetta May 17 '18 at 15:29
  • is that the result expectted : {B=bonjour, C=ciao, H=hello} ?, first leter as key, word as value – azro May 17 '18 at 15:30
  • @azro yes, exactly! – Giacomo Brunetta May 17 '18 at 15:31
  • @azro no no, the expected is: {B=bonjour, C=ciao, H=hello} – Giacomo Brunetta May 17 '18 at 15:31
  • 3
    I think you are misunderstanding something from your assignment, because this is not how typically these things work. What you probably want is a `Function` and then you would stream all the entries of the set to convert it to a `Map` – jbx May 17 '18 at 15:31
  • @AlfonsoSilvestri yeah, I guess I had missed the latest edit. [I reproduce your null](https://ideone.com/eyT2bn) after having removed the `setToList.apply(hs)` call which I guess correspond to a previous test. – Aaron May 17 '18 at 15:32
  • @jbx yes..but it is my first approach with these things, thus I want to understand how it works – Giacomo Brunetta May 17 '18 at 15:32
  • A general tip: don't use raw types, it makes it harder to keep track of what is going on. – Jorn Vernee May 17 '18 at 15:34
  • you probably also need `Map>` as you have two `hello` and `hallo` (both start with h) – Eugene May 17 '18 at 15:34
  • @Aaron sorry, setToList is other stuff, don't care about it – Giacomo Brunetta May 17 '18 at 15:35
  • The problem is that your `Function` creates a `HashMap` with a single entry that has the set both as key and value (s2 is the set, not one of its entries). Following what jbx said, you need instead a `Function>` which creates a map entry from a set entry, then stream the Set to map it to a Map – Aaron May 17 '18 at 15:35

4 Answers4

2

I think this means that you have to add all the words of the Set in the Map following 2 rules

  • the key is the first letter in uppercase
  • the value is the word

Function<Set<String>, Map<Character, String>> setToMap = aSet -> {
    Map<Character, String> map = new HashMap<>();
    for (String s : aSet ) {
        map.put(s.toUpperCase().charAt(0), s);
    }
    return map;
};
// or using Streams :
Function<Set<String>, Map<Character, String>> setToMap = aSet  -> 
      aSet.stream().collect(Collectors.toMap(s -> s.toUpperCase().charAt(0), 
                                             Function.identity(),
                                             (oldK, newK) -> oldK)); // merging function in cas of duplicate key

Tip: don't use raw types, but specify them as much as possible:

  • Function<Set,Map> becomes Function<Set<String>, Map<Character, String>>
azro
  • 53,056
  • 7
  • 34
  • 70
2

I bet that you misunderstood your problem a bit.

You probably want a function that gets the key from the value of each item you have in the set. So:

Set<String> set = new HashSet<>();
set.add("ciao");
set.add("hello");
set.add("bonjour");

Function<String, Character> keyExtractor = s -> Character.toUpperCase(s.charAt(0));

Map<Character, String> map = set.stream()
        .collect(Collectors.toMap(keyExtractor, Function.identity()));

This assumes you only have one word for each letter.

If you want to have more than one entry for each first letter then you can do:

Set<String> set = new HashSet<>();
set.add("ciao");
set.add("hello");
set.add("hallo");
set.add("bonjour");

Function<String, Character> keyExtractor = s -> Character.toUpperCase(s.charAt(0));

Map<Character, List<String>> map = set.stream()
        .collect(Collectors.groupingBy(keyExtractor));

If you wanted to do it without streams, it will be more complicated but possible:

Function<Set<String>, Map<Character, List<String>>> setConverter = set -> {
      Map<Character, List<String>> map = new HashMap<>();

      for (String s : set) {
        Character key = Character.toUpperCase(s.charAt(0));
        map.compute(key, (k, v) -> {
          if (v == null) {
            List<String> newList = new ArrayList<>();
            newList.add(s);
            return newList;
          } else {
            v.add(s);
            return v;
          }
        });
      }

      return map;
    };
jbx
  • 21,365
  • 18
  • 90
  • 144
1
public class Main {

public static void main(String[] args) {
    HashSet<String> hs = new HashSet<String>();
    hs.add("ciao");
    hs.add("hello");
    hs.add("hallo");
    hs.add("bonjour");
    //System.out.println(setToList.apply(hs));

    Function<Set<String>, Map<String,String>> setToMap = s2 -> {
        HashMap<String, String> map = new HashMap<>();
        for ( String o : s2)
        {
            map.put(o.toUpperCase(), o);
        }
            return map;
        };

    System.out.println(setToMap.apply(hs));
}
Ken.C
  • 41
  • 1
0
public class FunctionTest {

      public static void main(String[] args) {
           HashSet<String> hs = new HashSet<String>();
           hs.add("ciao");
           hs.add("hello");
           hs.add("hallo");
           hs.add("bonjour");

           Function<Set<String>,Map> function=set ->{

              Map<String,String> mapSet=new HashMap<>();

              set.forEach(valueOfSet->mapSet.put(valueOfSet.substring(0,1).toUpperCase(),valueOfSet));'

              return mapSet;
        };
        System.out.println(function.apply(hs));
   }
}

Without Using Function you can do it as below:

Map<String,String> mapSet=new HashMap<>();
hs.forEach(value->mapSet.put(value.substring(0,1),value));
System.out.println(mapSet);
derloopkat
  • 6,232
  • 16
  • 38
  • 45