Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Tuesday, March 8, 2016

Print Multimap in a order

Print Multimap in a order


I have a multimap with duplicate keys but with different values. Im trying to print them in a order given below. I already tried with iterator and while loop. However it printed same key values together. Please help me to understand how to print them in the order given below.

Original List

 key1 aaa   key1 bbb   key3 ggg   key2 sss   key2 eee   key4 aaa   key3 yyy  

Print Order.

 key1 aaa   key2 sss   key3 yyy   key4 aaa   key1 bbb   key2 eee   key3 ggg  

Answer by Friso for Print Multimap in a order


Are you using the right data structure for the problem? Looks like you actually want a List of Maps? Anyway to fix it:

Set sortedKeys = new HashSet<>(mm.keys());  for(int i = 0, n = 1; i < n; i++) {      for(String key : sortedKeys) {          List list = mm.get(key);          n = Math.max(n, list.size());          if (i < list.size()) {              System.out.printf("%s %s\n", key, list.get(i));          }      }  }  

It ain't pretty, but it does the job

Answer by Lostboy for Print Multimap in a order


Maybe you should use TreeMultimap?

    TreeMultimap mm = TreeMultimap.create();        mm.put("key1", "aaa");      mm.put("key1", "bbb");      mm.put("key3", "ggg");      mm.put("key2", "sss");      mm.put("key2", "eee");      mm.put("key4", "aaa");      mm.put("key3", "yyy");        for (String key : mm.keySet())      {          for (String value : mm.get(key))          {              System.out.printf("%s %s\n", key, value);          }      }  

Output:

key1 aaa  key1 bbb  key2 eee  key2 sss  key3 ggg  key3 yyy  key4 aaa  

Answer by arunpandianp for Print Multimap in a order


you could try something like

    TreeMultimap mm = TreeMultimap.create();      mm.put("key1", "aaa");      mm.put("key1", "bbb");      mm.put("key3", "ggg");      mm.put("key2", "sss");      mm.put("key2", "eee");      mm.put("key4", "aaa");      mm.put("key3", "yyy");      final List>> list = Lists.newLinkedList();      mm.asMap().entrySet().stream().forEach((i) -> {                  list.add(Maps.immutableEntry(i.getKey(), i.getValue().iterator()));              }      );      while (!list.isEmpty()) {          Map.Entry> e = list.get(0);          System.out.println(e.getKey() + " " + e.getValue().next());          if (e.getValue().hasNext()) {              list.add(list.get(0));          }          list.remove(0);      }  

Answer by roblovelock for Print Multimap in a order


Use a TreeMultimap to get the keys and values in natural order. Then you could build a list of strings you want to print by looping over the keys/values.

public static void main(String[] args) {        TreeMultimap mm = TreeMultimap.create();        mm.put("key1", "aaa");      mm.put("key1", "bbb");      mm.put("key3", "ggg");      mm.put("key2", "sss");      mm.put("key2", "eee");      mm.put("key4", "aaa");      mm.put("key3", "yyy");          List strings = new ArrayList<>();        for (String key : mm.keySet()) {            NavigableSet values = mm.get(key);          int i = 0;          for (String value : values) {              StringBuilder out;              if (strings.size() < i + 1) {                  out = new StringBuilder();                  strings.add(out);              } else {                  out = strings.get(i);                  out.append("\n");              }              out.append(key);              out.append(" ");              out.append(value);              i++;          }      }        strings.forEach(s -> {          System.out.println(s);      });  }  

This isn't 100% the same as your required order. However this is because the order of your values aren't in natural order or insertion order.

Answer by nhylated for Print Multimap in a order


As others have suggested, use a TreeMultiMap which sorts keys in their natural order and for each key, all values are sorted in natural order too.

But to print in the order that you want, the map will have to be iterated differently:

TreeMultimap mm = TreeMultimap.create();  mm.put("key1", "aaa");  mm.put("key1", "bbb");  mm.put("key3", "ggg");  mm.put("key2", "sss");  mm.put("key2", "eee");  mm.put("key4", "aaa");  mm.put("key3", "yyy");    // Use a copy of mm for the while loop if it needs to be retained.  while (!mm.isEmpty()) {      // Iterate over all distinct keys (Ki) just once, print their first values (Vi1) only and remove  from the map so that it's not printed again.       for (String key : new TreeSet(mm.keySet())) {          String value = mm.get(key).first();          System.out.println(key + " " + value);          mm.remove(key, value);      }  }  

After the first iteration of the while loop, these pairs will be printed and removed from the map:

  • key1 aaa
  • key2 sss
  • key3 ggg
  • key4 aaa

In the second iteration, there will be no key4 in the map and the remaining key, value pairs will be printed in order:

  • key1 bbb
  • key2 eee
  • key3 yyy

@arunpandianp's answer achieves the same result/output but this code is a bit simpler.

Edit: key3 - ggg will be printed before key3 - yyy

Answer by Evgeny Tanhilevich for Print Multimap in a order


I would agree that Multimap is not the best data structure for what you are trying to achieve; a Map of Lists might work better here. MultiMap sorts values according to their natural ordering (unless supplied with a custom comparator). If I understand it correctly, then what you need is ordering by insertion time (ignoring the ggg error in the expected output, pointed out by @Louis Wasserman). I cannot think of how to achieve that without changing the value type of the map from String to a custom class. The snippet below illustrates that.

TreeMultimap presents values as NavigableSet's, which don't alllow random acces (again, an argument for choosing another container) - hence the need to use a last value cache for interleaved output.

public class GuavaMultiMapTest {      private ComparableMapValue DUMMY = new ComparableMapValue(-1, null);      private TreeMultimap mm;      private int insertionCounter;        private class ComparableMapValue implements Comparable {          private final int index;          private final String value;            public ComparableMapValue(int index, String value) {              this.index = index;              this.value = value;          }            public ComparableMapValue(String value) {              this.value = value;              index = insertionCounter++;          }            public String getValue() {              return value;          }            @Override          public int compareTo(ComparableMapValue o) {              return this.index - o.index;          }            @Override          public String toString() {              return value;          }      }        private void put(String key, String value) {          mm.put(key, new ComparableMapValue(value));      }        public void testInterleavedOutput() {          mm = TreeMultimap.create();          put("key1", "aaa");          put("key1", "bbb");          put("key3", "ggg");          put("key2", "sss");          put("key2", "eee");          put("key4", "aaa");          put("key3", "yyy");            Map lastValues = new HashMap<>();          int dummyCount = 0;          while (dummyCount < mm.keySet().size()) {              for (String key : mm.keySet()) {                  NavigableSet navigableSet = mm.get(key);                  ComparableMapValue value = lastValues.containsKey(key) ? lastValues.get(key) : navigableSet.first();                  if (value == DUMMY) {                      continue;                  }                  System.out.printf("%s: %s%n", key, value);                  ComparableMapValue higher = navigableSet.higher(value);                  if (higher == null) {                      lastValues.put(key, DUMMY);                      dummyCount++;                  } else {                      lastValues.put(key, higher);                  }              }          }      }  }  

Answer by Steve K for Print Multimap in a order


If your aim is simply to print one value for each key in turn, it's a pretty simple algorithm, even if it seems to be a pretty weird one:

void printMultimap(Multimap map) {      // Sort your keys into an order you can iterate repeatedly      String[] keys = map.keySet().stream()          .sorted()          .filter(Objects::nonNull)          .toArray(String[]::new);        // Track how many values are printed.      AtomicInteger valuesPrinted = new AtomicInteger(0);        // Track how many times we've been through all the keys      AtomicInteger iterationIndex = new AtomicInteger(0);        // Calculate how many values we should be printing so we'll know when to stop      long totalNonNullValues = map.values().stream()                      .filter(Objects::nonNull)                      .count();        // We're done when we've printed as many values as the map contains      while (valuesPrinted.get() < totalNonNullValues) {                      // Getter for the current iteration's value for a given key          Function, String> getValueAtIndex = getterForIndex(iterationIndex);            for (String key : keys){              // When a value is printed, increment our counter              Consumer printAndMarkPrinted = printerForKey(valuesPrinted, key);                Optional.ofNullable(key)                  .map(map::get) // gets the list for the key                  .map(getValueAtIndex) // gets the value for the current iteration from the list                  .ifPresent(printAndMarkPrinted); // prints the value if present          }      }  }     Consumer printerForKey(AtomicInteger printCounter, String key) {      return (value)->{          printCounter.getAndIncrement();          System.out.println(key + " " + value);      };  }     Function, T> getterForIndex(AtomicInteger atomicIndex) {      return collection->collection.stream()          .sequential()          .skip(atomicIndex.getAndIncrement())          .findFirst()          .orElse(null);  }  

You could do more to optimize it and make it a bit smarter, but I opted to keep it as basic and legible as possible.


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.