TreeMap মান অনুসারে বাছাই করুন


137

আমি একটি তুলনামূলক লিখতে চাই যা আমাকে ডিফল্ট প্রাকৃতিক অর্ডারের পরিবর্তে একটি ট্রিম্যাপকে মান অনুসারে বাছাই করতে দেয়।

আমি এরকম কিছু চেষ্টা করেছি, তবে কী ভুল হয়েছে তা খুঁজে পাচ্ছি না:

import java.util.*;

class treeMap {
    public static void main(String[] args) {
        System.out.println("the main");
        byValue cmp = new byValue();
        Map<String, Integer> map = new TreeMap<String, Integer>(cmp);
        map.put("de",10);
        map.put("ab", 20);
        map.put("a",5);

        for (Map.Entry<String,Integer> pair: map.entrySet()) {
            System.out.println(pair.getKey()+":"+pair.getValue());
        }
    }
}

class byValue implements Comparator<Map.Entry<String,Integer>> {
    public int compare(Map.Entry<String,Integer> e1, Map.Entry<String,Integer> e2) {
        if (e1.getValue() < e2.getValue()){
            return 1;
        } else if (e1.getValue() == e2.getValue()) {
            return 0;
        } else {
            return -1;
        }
    }
}

আমি অনুমান করছি আমি যা জিজ্ঞাসা করছি তা: আমি কি Map.Entryতুলকের সাথে পাস করতে পারি ?


সম্ভবত এই আপনাকে সাহায্য করবে stackoverflow.com/questions/109383/...
Inv3r53


উত্তর:


179

আপনি TreeMapমানগুলিতে নিজের মতো বাছাই করতে পারবেন না , যেহেতু এটি SortedMapস্পেসিফিকেশনটিকে অস্বীকার করে :

একটি Mapযা এর কীগুলিতে মোট ক্রম সরবরাহ করে ।

যাইহোক, একটি বাহ্যিক সংগ্রহ ব্যবহার করে, আপনি সর্বদা বাছাই করতে পারেন Map.entrySet()তবে আপনি চানগুলি, মান বা দুটিয়ের সংমিশ্রণ (!!) দ্বারা চান wish

এখানে একটি জেনেরিক পদ্ধতি যে একটি ফেরৎ এর SortedSetএর Map.Entryদেওয়া একটি Mapযার মান Comparable:

static <K,V extends Comparable<? super V>>
SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
    SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
        new Comparator<Map.Entry<K,V>>() {
            @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                int res = e1.getValue().compareTo(e2.getValue());
                return res != 0 ? res : 1;
            }
        }
    );
    sortedEntries.addAll(map.entrySet());
    return sortedEntries;
}

এখন আপনি নিম্নলিখিতটি করতে পারেন:

    Map<String,Integer> map = new TreeMap<String,Integer>();
    map.put("A", 3);
    map.put("B", 2);
    map.put("C", 1);   

    System.out.println(map);
    // prints "{A=3, B=2, C=1}"
    System.out.println(entriesSortedByValues(map));
    // prints "[C=1, B=2, A=3]"

মনে রাখবেন যে মজাদার স্টাফগুলি ঘটবে যদি আপনি SortedSetনিজেই বা এর Map.Entryমধ্যে কোনওটি পরিবর্তন করার চেষ্টা করেন কারণ এটি আর মূল ম্যাপের মতো "ভিউ" entrySet()নয়।

সাধারণত বললে, মানচিত্রের মানগুলি এর মান অনুসারে বাছাই করার প্রয়োজনটি নীতিগত।


উপর দ্রষ্টব্য ==জন্যInteger

আপনার মূল তুলকটি Integerব্যবহার করে তুলনা করে ==। এই প্রায় সবসময় ভুল, যেহেতু ==সঙ্গে Integeroperands একটি রেফারেন্স সমতা, না মান সমতা হয়।

    System.out.println(new Integer(0) == new Integer(0)); // prints "false"!!!

সম্পর্কিত প্রশ্নগুলি


5
যদি আপনি ম্যাপ.পুট যোগ করেন ("ডি", 2); ফলাফলটি এখনও "[সি = 1, বি = 2, এ = 3]" এবং নয় "[সি = 1, বি = 2, ডি = 2, এ = 3]"
ইগোর মিল্লা

3
স্থির করুন: int res = e2.getValue ()। তুলনাটো (e1.getValue ()); প্রত্যাবর্তন পুনরায়! = 0? res: 1;
beshkenadze

নতুন পূর্ণসংখ্যা (0) == নতুন পূর্ণসংখ্যা (0) আপনি কোনও বস্তুর সাথে একটি রেফারেন্স তুলনা করেন এবং আপনি দুটি বস্তু তৈরি করেন! আউট পুট একেবারে সঠিক এবং অনুমানযোগ্য।
ইউরি চেরনিশভ

2
"সাধারণভাবে বলতে গেলে, মানচিত্রের মানগুলি এর মান অনুসারে বাছাই করার প্রয়োজন একেবারে নমনীয়" আমি এখানে একজন শিক্ষানবিস তবে আমার মনে হচ্ছে এটি করা খুব সাধারণ বিষয় হওয়া উচিত? উদাহরণস্বরূপ যদি আমি মানচিত্রে 3 প্রবীণ ব্যক্তিদের পুনরুদ্ধার করতে চাই {"আনা" = 37, "পিটার" = 43, "জন" = 4, "মেরি" = 15, "ম্যাট" = 78}
ফারটাগেইনটেক্সেদো

@ আইগরমিলার একটি সহজ কারণ রয়েছে, কেন আপনার কোডটি কাজ করে: অটোবক্সিংটি পূর্ণসংখ্যা.ভ্যালুওফ ব্যবহার করে। এবং এটিতে -128 থেকে 127 এর উদাহরণগুলির ক্যাশে রয়েছে!
জোকস্টার

75

বহুগুণের জন্য উত্তর প্রায় নিখুঁত। যদিও এটির একটি গুরুত্বপূর্ণ বাগ রয়েছে। এটি মানচিত্রের এন্ট্রিগুলি পরিচালনা করবে না যেখানে মানগুলি একই।

এই কোড: ...

Map<String, Integer> nonSortedMap = new HashMap<String, Integer>();
nonSortedMap.put("ape", 1);
nonSortedMap.put("pig", 3);
nonSortedMap.put("cow", 1);
nonSortedMap.put("frog", 2);

for (Entry<String, Integer> entry  : entriesSortedByValues(nonSortedMap)) {
    System.out.println(entry.getKey()+":"+entry.getValue());
}

আউটপুট হবে:

ape:1
frog:2
pig:3

আমাদের গাভীটি কীভাবে অদৃশ্য হয়ে গেছে তা নষ্ট হয়ে গেল নোট করুন "1" এর মানটি আমাদের এপসের সাথে: ও!

কোডের এই পরিবর্তনটি এই সমস্যার সমাধান করে:

static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
        SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
            new Comparator<Map.Entry<K,V>>() {
                @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                    int res = e1.getValue().compareTo(e2.getValue());
                    return res != 0 ? res : 1; // Special fix to preserve items with equal values
                }
            }
        );
        sortedEntries.addAll(map.entrySet());
        return sortedEntries;
    }

2
-1। আফাসিক কোনও Setবাস্তবায়নে একাধিকবার একটি উপাদান থাকে না । আপনি কেবল সেই সীমাবদ্ধতা লঙ্ঘন করেছেন। থেকে SortedSetএপিআই: নোট ক্রম একটি সাজানো সেট দ্বারা পরিচালিত যে সমান সঙ্গে সামঞ্জস্যপূর্ণ হতে হবে ... । সমাধানটি হবে একটি Listবাস্তবায়নে পরিবর্তন to
dacwe

4
@ ডাকা সমান মানগুলি কী নয়
বেলুম

1
@বেলাম: আমরা Setএখানে এস সম্পর্কে কথা বলছি । যেহেতু চুক্তি Comparatorলঙ্ঘন করে , ইত্যাদি কাজ করে না ! আদর্শে এই উদাহরণটি দেখুন । SetSet.removeSet.contains
dacwe

3
শুধু একটি নোট, যদি আপনি সুইচ int res= e1.getValue().compareTo(e2.getValue());মধ্যে int res= e2.getValue().compareTo(e1.getValue());, আপনি একটি সাজানো মান আরোহী পরিবর্তে অর্ডার রয়েছে।
tugcem

6
আমি বরং res != 0 ? res : e1.getKey().compareTo(e2.getKey())সমান মান সহ কীগুলির ক্রম সংরক্ষণ করতে ফিরে যাব ।
মার্কো ল্যাকোভিচ


17

একজন TreeMapহয় সবসময় কী অনুসারে সাজানো, অন্য কিছু অসম্ভব। একটি Comparatorনিছক আপনি নিয়ন্ত্রণ করতে পারবেন কিভাবে কী সাজানো হয়।

আপনি যদি সাজানো মান চান তবে আপনাকে সেগুলি একটিতে বের করে এনে Listবাছাই করতে হবে।


10

এটি ব্যবহার করে এটি করা যায় না Comparator, কারণ এটি সর্বদা তুলনা করার জন্য মানচিত্রের কীটি পাবেন । TreeMapশুধুমাত্র কী দ্বারা বাছাই করতে পারেন।


2
যদি ট্রিম্যাপটি কেবল তুলনাকারীর কাছে কীটি পাস করে, যদি আমি তুলনাকারীর নির্মাতার মধ্যে ট্রিম্যাপের একটি রেফারেন্স তৈরি করি তখন কি সম্ভব হবে, মানটি পাওয়ার জন্য কীটি ব্যবহার করে, এই জাতীয় কিছু (রেফারেন্স দিয়ে কীভাবে পাস হবে তা নিশ্চিত নয়): শ্রেণি বাই ভ্যালু তুলনামূলক {ট্রি ম্যাপ দ্য ট্রিটি প্রয়োগ করে; সর্বজনীন byValue (TreeMap theTree) {this.theTree = theTree; } পাবলিক ইনট তুলনা (স্ট্রিং কে 1, স্ট্রিং কে 2) {// ট্রি ম্যাপের getKey পদ্ধতিটি মান হিসাবে ব্যবহার করুন vit
ভিটো হুয়াং

1
@ ভিটো: না, কারণ সাধারণত দুটি কীগুলির মধ্যে একটি এখনও মানচিত্রে থাকবে না এবং আপনি এর মান পেতে সক্ষম হবেন না।
জোছিম সউর

এটি ট্রিম্যাপের তুলনাকারীর মধ্যে কাজ করার উদাহরণ নয়? (যদিও উপরে উল্লিখিত হিসাবে, এটি স্পেসিফিকেশনটি ভেঙে দেয় SortedMapযার জন্য কীগুলি বাছাই করার বিষয়টি নির্দিষ্ট করে) beginnersbook.com/2014/07/…
মার্কাস

@ মার্কাস: মান অনুসারে বাছাই করতে Comparatorএকটি বিদ্যমান মানচিত্র ব্যবহার করে। অন্য কথায়, এটি TreeMapপরে নির্ধারিত নির্বিচার মানগুলি বাছাই করতে পারে না , কেবলমাত্র মানগুলি যা ইতিমধ্যে মূল মানচিত্রে রয়েছে।
জোছিম সউর

5

Olof এর উত্তর ভাল জিনিস, কিন্তু এটি প্রয়োজন এক এটা নিখুঁত সামনে আরও একটি জিনিস। তার উত্তরের নীচে দেওয়া মন্তব্যে, ড্যাকউ (সঠিকভাবে) উল্লেখ করেছে যে তার প্রয়োগটি সেটগুলির জন্য তুলনা / সমান চুক্তি লঙ্ঘন করে। আপনি যদি কলটিতে কল করার চেষ্টা করেন বা সেটটিতে পরিষ্কারভাবে প্রবেশ করা একটি এন্ট্রি সরিয়ে ফেলেন, সেটটি কোডের কারণে সেটটিকে স্বীকৃতি দেবে না যা সমান মানের মান সহ এন্ট্রিগুলিকে সেটে স্থাপন করতে দেয়। সুতরাং, এটি ঠিক করার জন্য, কীগুলির মধ্যে সমতার জন্য আমাদের পরীক্ষা করা দরকার:

static <K,V extends Comparable<? super V>> SortedSet<Map.Entry<K,V>> entriesSortedByValues(Map<K,V> map) {
    SortedSet<Map.Entry<K,V>> sortedEntries = new TreeSet<Map.Entry<K,V>>(
        new Comparator<Map.Entry<K,V>>() {
            @Override public int compare(Map.Entry<K,V> e1, Map.Entry<K,V> e2) {
                int res = e1.getValue().compareTo(e2.getValue());
                if (e1.getKey().equals(e2.getKey())) {
                    return res; // Code will now handle equality properly
                } else {
                    return res != 0 ? res : 1; // While still adding all entries
                }
            }
        }
    );
    sortedEntries.addAll(map.entrySet());
    return sortedEntries;
}

"নোট করুন যে সাজানো সেট দ্বারা পরিচালিত ক্রমটি (সুস্পষ্ট তুলনামূলক সরবরাহ করা হবে কিনা) অবশ্যই বাছাই করা সেটটি যদি সঠিকভাবে সেট ইন্টারফেসটি প্রয়োগ করতে হয় ... সেট ইন্টারফেসটি সমান ক্রিয়াকলাপের ক্ষেত্রে সংজ্ঞায়িত করা হয় , তবে একটি সাজানো সেট তার তুলনা টো (বা তুলনা) পদ্ধতিটি ব্যবহার করে সমস্ত উপাদানগুলির তুলনা সম্পাদন করে, সুতরাং এই পদ্ধতির দ্বারা সমান হিসাবে গণ্য করা দুটি উপাদান, বাছাই করা সেটটির দৃষ্টিকোণ থেকে সমান । " ( http://docs.oracle.com/javase/6/docs/api/java/util/SortSet.html )

যেহেতু আমরা সেটটিকে সমান মূল্যবান এন্ট্রি যুক্ত করতে বাধ্য করতে প্রথমে সাম্যতাকে অগ্রাহ্য করেছি, এখন আপনার কী সন্ধানের প্রবেশদ্বারটি প্রকৃতপক্ষে ফিরে আসার জন্য সেটটি সেট করার জন্য এখন কীগুলির মধ্যে সমতার জন্য পরীক্ষা করতে হবে। এটি কিন্ডা অগোছালো এবং অবশ্যই সেটগুলি কীভাবে ব্যবহারের উদ্দেশ্যে করা হয়েছিল তা নয় - তবে এটি কার্যকর হয়।


3

আমি জানি এই পোস্টটি বিশেষত মান দ্বারা একটি ট্রিম্যাপ বাছাই করার জন্য বলেছে, তবে আমাদের মধ্যে যারা বাস্তবিকাই বাস্তবায়নের বিষয়ে চিন্তা করেন না তবে এমন একটি সমাধান চান যা সংগ্রহকে উপাদান হিসাবে যুক্ত হিসাবে সাজানো রাখে, আমি এই ট্রিসেট-ভিত্তিক প্রতিক্রিয়াটির প্রশংসা করব সমাধান। একটির জন্য, উপাদানগুলি কী দ্বারা সহজেই পুনরুদ্ধার করা যায় না, তবে ব্যবহারের ক্ষেত্রে আমার হাতে ছিল (সর্বনিম্ন মানগুলির সাথে এন কীগুলি সন্ধান করা), এটি কোনও প্রয়োজন ছিল না।

  TreeSet<Map.Entry<Integer, Double>> set = new TreeSet<>(new Comparator<Map.Entry<Integer, Double>>()
  {
    @Override
    public int compare(Map.Entry<Integer, Double> o1, Map.Entry<Integer, Double> o2)
    {
      int valueComparison = o1.getValue().compareTo(o2.getValue());
      return valueComparison == 0 ? o1.getKey().compareTo(o2.getKey()) : valueComparison;
    }
  });
  int key = 5;
  double value = 1.0;
  set.add(new AbstractMap.SimpleEntry<>(key, value));

2

অনেক লোক শুনতে পান যে তালিকা ব্যবহারের পরামর্শ দেওয়া হয়েছে এবং আমি এটি ব্যবহার করতেও পছন্দ করি

মানচিত্রের মানগুলি অনুসারে তাদের প্রবেশক্রমগুলি সাজানোর জন্য এখানে দুটি পদ্ধতি রয়েছে are

    static final Comparator<Entry<?, Double>> DOUBLE_VALUE_COMPARATOR = 
        new Comparator<Entry<?, Double>>() {
            @Override
            public int compare(Entry<?, Double> o1, Entry<?, Double> o2) {
                return o1.getValue().compareTo(o2.getValue());
            }
        };

        static final List<Entry<?, Double>> sortHashMapByDoubleValue(HashMap temp)
        {
            Set<Entry<?, Double>> entryOfMap = temp.entrySet();

            List<Entry<?, Double>> entries = new ArrayList<Entry<?, Double>>(entryOfMap);
            Collections.sort(entries, DOUBLE_VALUE_COMPARATOR);
            return entries;
        }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.