2016-02-29 53 views
-2

我有重複鍵,但不同的價值觀多重映射。我試圖按照下面給出的順序打印它們。我已經嘗試了迭代器和while循環。但是它將相同的鍵值打印在一起。請幫助我瞭解如何按照下面給出的順序打印它們。打印Multimap之在爲了

原版

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

打印命令。

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

您正在使用哪個多圖?它來自番石榴嗎? – sprinter

+0

@sprinter是的。我使用番石榴multimap。我會更新這個問題。 – amal

+0

該命令將很難實施。大多數多圖都會將相同密鑰的條目一起存儲在列表中。你可以迭代多次,每次只打印第n個這樣的條目,直到沒有更多。 – Thilo

回答

0

您對問題使用正確的數據結構嗎?看起來你真的想要一個地圖列表?反正來解決它:

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

這是不漂亮,但它的工作

1

也許你應該使用TreeMultimap?

TreeMultimap<String, String> 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); 
     } 
    } 

輸出:

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

Thankx。但那不是我想要的順序。訂單應該是key1,key2,key3,key4,key1,key2,key3 – amal

0

你可以嘗試像

TreeMultimap<String, String> 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<Map.Entry<String, Iterator<String>>> list = Lists.newLinkedList(); 
    mm.asMap().entrySet().stream().forEach((i) -> { 
       list.add(Maps.immutableEntry(i.getKey(), i.getValue().iterator())); 
      } 
    ); 
    while (!list.isEmpty()) { 
     Map.Entry<String, Iterator<String>> e = list.get(0); 
     System.out.println(e.getKey() + " " + e.getValue().next()); 
     if (e.getValue().hasNext()) { 
      list.add(list.get(0)); 
     } 
     list.remove(0); 
    } 
0

使用TreeMultimap得到的自然順序鍵和值。然後,您可以通過遍歷鍵/值來創建要打印的字符串列表。

public static void main(String[] args) { 

    TreeMultimap<String, String> 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<StringBuilder> strings = new ArrayList<>(); 

    for (String key : mm.keySet()) { 

     NavigableSet<String> 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); 
    }); 
} 

這與您所需的訂單不是100%相同。但是,這是因爲您的值的順序不是自然順序或插入順序。

0

正如其他人所建議的,使用TreeMultiMap這在它們的自然順序,併爲每個鍵排序鍵,所有值都在自然順序排序了。

但您希望以打印,地圖會以不同的方式重複:

TreeMultimap<String, String> 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 <Ki, Vi1> 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); 
    } 
} 

while循環的第一次迭代後,這些對將被打印並且從地圖上刪除:

  • key1的AAA
  • 鍵2 SSS
  • KEY3 GGG
  • KEY4 AAA

在第二次迭代中,將有在地圖上沒有KEY4,其餘鍵,值對將被打印,以便:

  • KEY1 BBB
  • KEY2 EEE
  • KEY3 YYY

@ arunpandianp的答案達到了相同的結果/輸出,但是這個代碼有點簡單。

編輯:KEY3 - GGG將KEY3之前打印 - YYY

0

我同意Multimap是不是你想要達到的最好的數據結構; ListsMap可能在這裏效果更好。 MultiMap根據它們的自然排序值(除非提供自定義比較器)。如果我理解正確,那麼您需要的是按插入時間排序(忽略@Louis Wasserman指出的期望輸出中的ggg錯誤)。如果不將地圖的值類型從String更改爲自定義類,我無法想象如何實現這一點。下面的代碼片段說明了這一點。

TreeMultimap呈現值NavigableSet的,不alllow隨機存取權限(再次,如何選擇其他容器參數) - 因此需要使用最後一個值緩存交織輸出。

public class GuavaMultiMapTest { 
    private ComparableMapValue DUMMY = new ComparableMapValue(-1, null); 
    private TreeMultimap<String, ComparableMapValue> mm; 
    private int insertionCounter; 

    private class ComparableMapValue implements Comparable<ComparableMapValue> { 
     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<String, ComparableMapValue> lastValues = new HashMap<>(); 
     int dummyCount = 0; 
     while (dummyCount < mm.keySet().size()) { 
      for (String key : mm.keySet()) { 
       NavigableSet<ComparableMapValue> 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); 
       } 
      } 
     } 
    } 
} 
0

如果你的目標僅僅是打印一個值依次對每個關鍵,這是一個非常簡單的算法,即使它似乎是一個很奇怪的一個:

void printMultimap(Multimap<String, String> 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<Collection<String>, String> getValueAtIndex = getterForIndex(iterationIndex); 

     for (String key : keys){ 
      // When a value is printed, increment our counter 
      Consumer<String> 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 
     } 
    } 
} 

<T> Consumer<String> printerForKey(AtomicInteger printCounter, String key) { 
    return (value)->{ 
     printCounter.getAndIncrement(); 
     System.out.println(key + " " + value); 
    }; 
} 

<T> Function<Collection<T>, T> getterForIndex(AtomicInteger atomicIndex) { 
    return collection->collection.stream() 
     .sequential() 
     .skip(atomicIndex.getAndIncrement()) 
     .findFirst() 
     .orElse(null); 
} 

你可以做更多優化它並使其更加智能化,但我選擇儘可能保持基本和清晰。