মানচিত্র থেকে আলাদা মান সহ কীভাবে উত্পাদন করবেন (এবং বাইনারিঅ্যাপেটর ব্যবহার করে সঠিক কীটি ব্যবহার করবেন)?


13

আমার একটি মানচিত্র রয়েছে Map<K, V>এবং আমার লক্ষ্য হ'ল সদৃশ মানগুলি মুছে ফেলা এবং Map<K, V>আবার একই কাঠামোর আউটপুট । যদি সদৃশ মান পাওয়া যায়, এক কী (নির্বাচিত করা উচিত kদুটো কী (সম্ভাব্য) k1এবং k1) যা এই মান ধরে রাখুন, এই কারণে, অনুমান BinaryOperator<K>দান kথেকে k1এবং k2পাওয়া যায়।

ইনপুট এবং আউটপুট উদাহরণ:

// Input
Map<Integer, String> map = new HashMap<>();
map.put(1, "apple");
map.put(5, "apple");
map.put(4, "orange");
map.put(3, "apple");
map.put(2, "orange");

// Output: {5=apple, 4=orange} // the key is the largest possible

ব্যবহার করে আমার প্রয়াস Stream::collect(Supplier, BiConsumer, BiConsumer)হয় একটু খুব কদাকার এবং যেমন চপল অপারেশন রয়েছে Map::putএবং Map::removeযা আমি এড়াতে চাই:

// // the key is the largest integer possible (following the example above)
final BinaryOperator<K> reducingKeysBinaryOperator = (k1, k2) -> k1 > k2 ? k1 : k2;

Map<K, V> distinctValuesMap = map.entrySet().stream().collect(
    HashMap::new,                                                              // A new map to return (supplier)
    (map, entry) -> {                                                          // Accumulator
        final K key = entry.getKey();
        final V value = entry.getValue();
        final Entry<K, V> editedEntry = Optional.of(map)                       // New edited Value
            .filter(HashMap::isEmpty)
            .map(m -> new SimpleEntry<>(key, value))                           // If a first entry, use it
            .orElseGet(() -> map.entrySet()                                    // otherwise check for a duplicate
                    .stream() 
                    .filter(e -> value.equals(e.getValue()))
                    .findFirst()
                    .map(e -> new SimpleEntry<>(                               // .. if found, replace
                            reducingKeysBinaryOperator.apply(e.getKey(), key), 
                            map.remove(e.getKey())))
                    .orElse(new SimpleEntry<>(key, value)));                   // .. or else leave
        map.put(editedEntry.getKey(), editedEntry.getValue());                 // put it to the map
    },
    (m1, m2) -> {}                                                             // Combiner
);

কোনও কলের Collectorsমধ্যে উপযুক্ত সংমিশ্রণটি ব্যবহার করে কী কোনও সমাধান রয়েছে Stream::collect(যেমন: পরিবর্তনীয় অপারেশনগুলি ছাড়াই)?


2
" আরও ভাল " বা " সেরা " এর জন্য আপনার মেট্রিকগুলি কী ? Streamএস এর মাধ্যমে কি করা উচিত ?
টুরিং 85

যদি একই মানটি 2 টি কী এর সাথে যুক্ত থাকে তবে আপনি কী কী ধরে রাখবেন তা কীভাবে চয়ন করবেন?
মাইকেল

আপনার ক্ষেত্রে প্রত্যাশিত আউটপুট কি?
ওয়াইসিএফ_এল

1
@ ট্যুরিং 85: যেমনটি আমি বলেছি। এর মধ্যে বা এর মধ্যে পরিবর্তনযোগ্য মানচিত্রের কোনও সুস্পষ্ট ব্যবহার না করাই ভাল বা সেরাMap::putMap::removeCollector
নিকোলাস

উত্তর:


12

আপনি সংগ্রাহক. টোম্যাপ ব্যবহার করতে পারেন

private Map<Integer, String> deduplicateValues(Map<Integer, String> map) {
    Map<String, Integer> inverse = map.entrySet().stream().collect(toMap(
            Map.Entry::getValue,
            Map.Entry::getKey,
            Math::max) // take the highest key on duplicate values
    );

    return inverse.entrySet().stream().collect(toMap(Map.Entry::getValue, Map.Entry::getKey));
}

9

এটি ব্যবহার করে দেখুন: সরল উপায় হ'ল কী এবং মানটি বিপরীত হয় তবে toMap()মার্জ ফাংশন সহ সংগ্রাহক ব্যবহার করুন ।

map.entrySet().stream()
        .map(entry -> new AbstractMap.SimpleEntry<>(entry.getValue(), entry.getKey()))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, reducingKeysBinaryOperator));

Map<K, V> output = map.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey, reducingKeysBinaryOperator))
        .entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));

2
মধ্যবর্তী mapঅপারেশন কী কিনে তা দেখতে আমি ব্যর্থ । আপনি কী এবং মানগুলি অদলবদলের বলে মনে করছেন, এটি অনেকটা পরিষ্কার, তবে কী কথা, আপনি সংগ্রহের ধাপে এটি একইভাবে করতে পারেন?
জিপিআই

3
@ জিপিআই এবং মাইকেল, এটি কারণ কীগুলি একীভূত করতে হবে, তাই জোড়গুলি কীগুলি একত্রিত করবে। যা অনুপস্থিত তা হ'ল দ্বিতীয় বিপর্যয়।
জিন-ব্যাপটিস্ট ইউনূস

2
@ হাডিজি না! বিপরীতটি সঠিক ছিল! তবে দ্বিতীয়টি ফিরে আসার দরকার ছিল।
মার্জগুলি

@ জিন-ব্যাপটিস্ট ইউনুস আমি একীভূত হওয়ার প্রয়োজনীয়তা বুঝতে পেরেছি, তবে কেন আমি তাত্ক্ষণিকভাবে তা পাচ্ছি না কেন swap(); collect(key, value, binOp);তার পরিবর্তে আপনার কোড কেন collect(value, key, binOp)। বাস্তবের জন্য আমার কি এই চেষ্টা করা দরকার?
জিপিআই

2
আপনার দ্বারা ভাগ করা কোডে প্রশ্নে প্রবর্তিত স্থানীয় পরিবর্তনশীলটি ব্যবহার করার জন্য স্বাধীনতা নিয়েছে। আপনি উত্তরটি দেওয়ার সময় যদি উদ্দেশ্যটি বিরোধিত হয় তবে সেটিকে ফিরিয়ে দিন।
নমন

4

আমি নন-স্ট্রিমগুলির সমাধানটিকে আরও অভিব্যক্তিপূর্ণ বলে মনে করি:

BinaryOperator<K> reducingKeysBinaryOperator = (k1, k2) -> k1 > k2 ? k1 : k2;

Map<V, K> reverse = new LinkedHashMap<>(map.size());
map.forEach((k, v) -> reverse.merge(v, k, reducingKeysBinaryOperator));

Map<K, V> result = new LinkedHashMap<>(reverse.size());
reverse.forEach((v, k) -> result.put(k, v));

এটি Map.mergeআপনার হ্রাস দ্বি-ফাংশন ব্যবহার করে এবং LinkedHashMapআসল এন্ট্রি ক্রম সংরক্ষণ করতে ব্যবহার করে।


2
হ্যাঁ, আমি এই (অনুরূপ) সমাধানটি শেষ করেছি। যাইহোক, আমি জাভা-প্রবাহের পদ্ধতির সন্ধান করছি, যেহেতু এটি উপায়টি আরও ঘোষণামূলক। আমার +1 করুন
নিকোলাস

1

আমি Collectorsফিরে আসা মানচিত্রটি পুনরায় সংগ্রহ এবং আরও প্রক্রিয়াজাতকরণের প্রয়োজন ছাড়া কেবল ব্যবহারের একটি উপায় পেয়েছি । ধারণাটি হ'ল:

  1. গ্রুপ Map<K, V>থেকে Map<V, List<K>

    Map<K, V> distinctValuesMap = this.stream.collect(
        Collectors.collectingAndThen(
            Collectors.groupingBy(Entry::getValue),
            groupingDownstream 
        )
    );

    {আপেল = [1, 5, 3], কমলা = [4, 2]}

  2. নতুন কী ( List<K>) Kব্যবহার করতে হ্রাস করুন BinaryOperator<K>

    Function<Entry<V, List<Entry<K, V>>>, K> keyMapFunction = e -> e.getValue().stream()
        .map(Entry::getKey)
        .collect(Collectors.collectingAndThen(
            Collectors.reducing(reducingKeysBinaryOperator),
            Optional::get
        )
    );

    {আপেল = 5, কমলা = 4

  3. Map<V, K>পিছনে Map<K, V>আবার কাঠামোর বিপরীত করুন - যা নিরাপদ যেহেতু উভয় কী এবং মান পৃথক হিসাবে গ্যারান্টিযুক্ত।

    Function<Map<V, List<Entry<K,V>>>, Map<K, V>> groupingDownstream = m -> m.entrySet()
        .stream()
        .collect(Collectors.toMap(
            keyMapFunction,
            Entry::getKey
        )
    );

    {5 = আপেল, 4 = কমলা}

চূড়ান্ত কোড:

final BinaryOperator<K> reducingKeysBinaryOperator = ...

final Map<K, V> distinctValuesMap = map.entrySet().stream().collect(
        Collectors.collectingAndThen(
            Collectors.groupingBy(Entry::getValue),
            m -> m.entrySet().stream().collect(
                Collectors.toMap(
                    e -> e.getValue().stream().map(Entry::getKey).collect(
                        Collectors.collectingAndThen(
                            Collectors.reducing(reducingKeysBinaryOperator),
                            Optional::get
                        )
                    ),
                    Entry::getKey
                )
            )
        )
    );

1

"স্ট্রিম এবং কালেক্টরস.স্রোপিংবি" দিয়ে কাঙ্ক্ষিত ফলাফল পাওয়ার জন্য আরেকটি পন্থা।

    map = map.entrySet().stream()
    .collect(Collectors.groupingBy(
            Entry::getValue,
            Collectors.maxBy(Comparator.comparing(Entry::getKey))
            )
    )
    .entrySet().stream()
    .collect(Collectors.toMap(
            k -> {
                return k.getValue().get().getKey();
            }, 
            Entry::getKey));
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.