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