2015-07-04 22 views
7

साथ अटक रहा Person वर्ग है:लैम्ब्डा अभिव्यक्ति और मानचित्र

import java.util.*; 
public class Person { 
    private String name; 
    Map<String,Integer> Skills=new HashMap<>(); // skill name(String) and level(int) 

    public String getName(){ 
     return this.name; 
    } 
    public Map<String,Integer> getSkills(){ 
     return this.Skills; 
    } 
} 

और App वर्ग:

import java.util.*; 
import java.util.Map.Entry; 
import static java.util.stream.Collectors.*; 
import static java.util.Comparator.*; 
public class App { 
    private List<Person> people=new ArrayList<>(); // the people in the company 

    public Map<String,Set<String>> PeoplePerSkill(){ 
     return this.people.stream().collect(groupingBy(p-> p.getSkills().keySet() //<-get 
                      //^problem here 
            ,mapping(Person::getName,toSet()))); 
    } 
} 

App कक्षा में PeoplePerSkill विधि के अनुसार लोगों के नामों की Set वापस जाने के लिए की जरूरत है कौशल। इसका मतलब है कि एक कौशल कई लोगों के स्वामित्व में हो सकता है।

मैं groupingBy(p->p...........,) के साथ फंस मैं सिर्फ कौशल के नाम का String नहीं मिल सकता है, मैं कई मायनों कोशिश की, लेकिन चीजों को वर्तमान में मेरे कोड लौटाता है Map<Object, Set<String>>

उत्तर

6
तरह से अजनबी मिल :(।

वैसे,

आप फ्लैट मानचित्रण के माध्यम से यह कर सकते हैं, हालांकि यह शायद बहुत ही सुंदर नहीं लगती है:

public Map<String,Set<String>> PeoplePerSkill(){ 
    return this.people.stream() 
     .<Entry<String, String>>flatMap(p -> 
      p.getSkills().keySet() 
       .stream() 
       .map(s -> new AbstractMap.SimpleEntry<>(s, p.getName()))) 
     .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toSet()))); 
} 

यहाँ flatMap जोड़े (skill, person name) की एक धारा है, जो col हैं बनाता है आपके जैसा ही तरीके से व्याख्यान। मैं जोड़ी का प्रतिनिधित्व करने के लिए AbstractMap.SimpleEntry कक्षा का उपयोग कर रहा हूं, आप कुछ और उपयोग कर सकते हैं।

मेरी StreamEx पुस्तकालय इस कार्य का उपयोग करते हुए खूबसूरत हल किया जा सकता:

return StreamEx.of(this.people) 
     .mapToEntry(p -> p.getSkills().keySet(), Person::getName) 
     .flatMapKeys(Set::stream) 
     .grouping(toSet()); 

आंतरिक यह लगभग एक ही है, बस वाक्यात्मक चीनी है।

अद्यतन: लगता है कि अपने मूल समाधान गलत था: यह नक्शा person_name -> [skills] लौट आए, लेकिन अगर मैं ओपी सही ढंग से समझ, वह नक्शा skill -> [person_names] चाहता है। जवाब संपादित किया गया।

1

मुझे यकीन नहीं है कि धाराएं आपके जीवन को यहां आसान बनाती हैं या नहीं। आईएमओ इस कोड को पढ़ने और क्लीनर के लिए बहुत आसान है।

public Map<String, Set<String>> peoplePerSkill() { 

    Map<String, Set<String>> map = new HashMap<>(); 

    for (Person person : people) { 
     for (String skill : person.getSkills().keySet()) { 
      map.putIfAbsent(skill, new HashSet<>()); 
      map.get(skill).add(person.getName()); 
     } 
    } 

    return map; 
} 

आप अपने कोड में बाहरी पुस्तकालयों का उपयोग कर सकते हैं आप "को आसान बनाने में"

map.computeIfAbsent(skill, k -> new HashSet<>()).add(person.getName()); 
1

साथ

map.putIfAbsent(skill, new HashSet<>()); 
map.get(skill).add(person.getName()); 

कर सकते हैं, तो आप एक Map<String, Set<String>> के बजाय एक Multimap उपयोग करने पर विचार करना चाह सकते हैं । दुर्भाग्य से, एक समाधान एक Multimap का उपयोग कर अधिक बॉयलरप्लेट की आवश्यकता होती है, क्योंकि यह आधिकारिक तौर पर JDK द्वारा समर्थित नहीं है जा रहा है, लेकिन यह एक "स्वच्छ" समाधान के लिए नेतृत्व करना चाहिए:

public static void main(String[] args) { 
    Person larry = new Person("larry"); 
    larry.getSkills().put("programming", 0); 
    larry.getSkills().put("cooking", 0); 

    Person nishka = new Person("nishka"); 
    nishka.getSkills().put("programming", 0); 
    nishka.getSkills().put("cooking", 0); 

    Person mitul = new Person("mitul"); 
    mitul.getSkills().put("running", 0); 
    mitul.getSkills().put("cooking", 0); 

    Person rebecca = new Person("rebecca"); 
    rebecca.getSkills().put("running", 0); 
    rebecca.getSkills().put("programming", 0); 

    List<Person> people = Arrays.asList(larry, nishka, mitul, rebecca); 

    Multimap<String, String> peopleBySkills = people.stream().collect(
     collectingAndThen(toMap(Person::getName, p -> p.getSkills().keySet()), 
      CollectingMultimap.<String, String, Set<String>> toMultimap() 
       .andThen(invert()))); 
    System.out.println(peopleBySkills); 
    } 

    private static <K, V, I extends Iterable<V>> Function<Map<K, I>, Multimap<K, V>> toMultimap() { 
    return m -> { 
     Multimap<K, V> map = ArrayListMultimap.create(); 
     m.entrySet().forEach(e -> map.putAll(e.getKey(), e.getValue())); 
     return map; 
    }; 
    } 

    private static <K, V> Function<Multimap<K, V>, Multimap<V, K>> invert() { 
    return m -> { 
     return Multimaps.invertFrom(m, ArrayListMultimap.create()); 
    }; 
    } 

{running=[mitul, rebecca], cooking=[nishka, larry, mitul], programming=[nishka, larry, rebecca]} 

सूचना कैसे मुझे जेनेरिक पैरामीटर toMultimap() पर आपूर्ति करना पड़ा। जावा 8 में बहुत बेहतर सामान्य अनुमान है, लेकिन यह does not infer chained method calls है।

कंपाइलर को टाइप पैरामीटर को सही ढंग से अनुमान लगाने के लिए आपको या तो सामान्य पैरामीटर को स्पष्ट रूप से आपूर्ति करने या स्थानीय चर Function<Map<String, Set<String>>, Multimap<String, String>> toMultimap घोषित करने की आवश्यकता होगी।

संबंधित मुद्दे