3

I would like to override System.out.println(map) to print not 

{A=1, B=2, C=3,...}

but 

 A 1
 B 2
 C 3
 ...

just like what I have done in readData function of MapManager class.

I have found some code that could be the hint for the solution from the definition code of AbstractMap<K,V> which is extended by TreeMap<K,V> and implements Map<K,V> In the definition of AbstractMap<K,V>, toString() is implemented like below:

 public String toString() {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        if (! i.hasNext())
         return "{}";
        StringBuilder sb = new StringBuilder();
        sb.append('{'); 
        for (;;) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key); 
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value);
            if (! i.hasNext()) return sb.append('}').toString();
            sb.append(',').append(' ');
             }
        }

If I would modify this code to make it does what I intend it to do, it would be like this:

public String toString() {
    Iterator<Entry<K,V>> i = entrySet().iterator();
    if (! i.hasNext())return "{}";
    StringBuilder sb = new StringBuilder(); 
    sb.append('{');
    for (;;) {
        Entry<K,V> e = i.next();
        K key = e.getKey();
        V value = e.getValue();sb.append(key   == this ? "(this Map)" : key);
        sb.append(' ');  //whitespace instead of ‘=’
        sb.append(value == this ? "(this Map)" : value);
        if (! i.hasNext())return sb.toString();// make sb into String without appending anything.
        sb.append('\n'); //append newline instead of ‘,’ and ‘ ’
    }
}

BUT added to this, I would like to print the map’s entries in the ascending order of value and the alphabetical order of key, so what I want println to do is what the following instructions would do:

set = box.entrySet();
list = new ArrayList<>(set);
Collections.sort(list, new ValueComparator<Map.Entry<String, Double>>());
    
Iterator<Map.Entry<String, Double>> it = list.iterator();
while(it.hasNext()) {
    Map.Entry<String, Double> entry = it.next();
    double value = entry.getValue().doubleValue();
    System.out.println(entry.getKey() + " " + value);
}

How could I do overrinding in my code to achieve this? One important constraint is that I must not modify the code inside public class Problem{ }.

Below is the entire code that I wrote:

import java.util.*;
import java.util.Map.Entry;
import java.io.*;

class MapManager{
    private static BufferedReader br;
    private static Set<Map.Entry<String, Double>> set;
    private static List<Map.Entry<String, Double>> list;

    static class ValueComparator<T> implements Comparator<T>{
        public int compare(Object o1, Object o2) {
            if(o1 instanceof Map.Entry && o2 instanceof Map.Entry) {
                Map.Entry<String, Double> e1 = (Map.Entry<String, Double>) o1;
                Map.Entry<String, Double> e2 = (Map.Entry<String, Double>) o2;
                double v1 = e1.getValue().doubleValue();
                double v2 = e2.getValue().doubleValue();
                return (int)(v1 - v2);
            }
            return -1;
        }
    }

    public static TreeMap<String, Double> readData(String fn){
        TreeMap<String, Double> box = new TreeMap<>();
        int data = 0, i = 0, j = 0, digits = 0, points = 0;
        String buffer = " ";
        String name = " ";
        String price = " ";

    (omitted)

        set = box.entrySet();
        list = new ArrayList<>(set);
        Collections.sort(list, new ValueComparator<Map.Entry<String, Double>>());
    
        Iterator<Map.Entry<String, Double>> it = list.iterator();
        while(it.hasNext()) {
            Map.Entry<String, Double> entry = it.next();
            double value = entry.getValue().doubleValue();
            System.out.println(entry.getKey() + " " + value);
        }

        return box;
    }
}
public class Problem {
    public static void main(String[] args) {
        Map<String, Double> map = MapManager.readData("input.txt");
        if(map == null) {
            System.out.println("Input file not found.");
            return;
        }
        System.out.println(map);
    }
}
hjy
  • 31
  • 2
  • 6
    You'd have to extend `TreeMap` and override the `toString()` method. Then make your `MapManager.readData()` return your custom map instead of a standard `TreeMap`. – Robby Cornelissen Nov 27 '20 at 01:37

2 Answers2

3

Just create your map with an overridden toString method. You can either assign this to an interface type or a TreeMap type.

Map<String,Double> map = new TreeMap<>() {
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Entry<?,?> e : this.entrySet()) {
            sb.append(String.format("%s %s%n", e.getKey(), e.getValue()));
        }
        return sb.toString();
    }
};
    
    
map.put("A",1.0);
map.put("B",2.0);
map.put("C",3.0);
    
System.out.println(map);

Prints

A 1.0
B 2.0
C 3.0

Another suggestion. If you must write your own Comparator, then don't do this.

 return (int)(v1 - v2);

It's bad form. Take the time and return -1, 1, or 0. You can do it easily using the ternary operator (?:).

 return v1 > v2 ? 1 : v1 < v2 ? -1 : 0;

But even better would be to use the comparator provided by the Map.Entry class.

Comparator<Entry<String,Double>> valueComparator = Entry.comparingByValue();
Collections.sort(List, valueComparator);
        

WJS
  • 36,363
  • 4
  • 24
  • 39
2

I don't know what's the relation of the question and your class MapManager.

Only for the question how to override System.out.println(map). You can override System.out.

public class Q65031068 {
  public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<>();
    map.put("A", 1);
    map.put("B", 2);
    map.put("C", 3);
    System.out.println(map);
    PrintStream out = System.out;
    System.setOut(new PrintStream(out) {
      @Override
      public void println(Object o) {
        if (o instanceof Map) {
          super.println(((Map<?, ?>) o).entrySet().stream()
            .map(e -> String.format("%s %s", e.getKey(), e.getValue()))
            .collect(Collectors.joining("\n")));
        } else {
          super.println(o);
        }
      }
    });
    System.out.println(map);
  }
}

Output:

{A=1, B=2, C=3}
A 1
B 2
C 3
Dean Xu
  • 4,438
  • 1
  • 17
  • 44