2016-02-29 4 views
-2

У меня есть мультиплеер с дубликатными ключами, но с разными значениями. Я пытаюсь напечатать их в порядке, указанном ниже. Я уже пробовал с итератором и while loop. Однако он печатал одинаковые значения ключей вместе. Пожалуйста, помогите мне понять, как печатать их в порядке, указанном ниже.Печать Multimap в заказе

Оригинал Список

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 
+0

Какой тип мулимитатора вы используете? Это из Гуавы? – sprinter

+0

@sprinter Да. Я использую многоадресную рассылку Guava. Я обновлю вопрос. – amal

+0

Этот порядок будет сложным для реализации. Большинство мультикадров будут хранить записи для одного и того же ключа вместе в списке. Вы можете повторять много раз, каждый раз печатайте 'n'th такую ​​запись только, пока их больше нет. – 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. Но это не тот порядок, который я хочу. Заказ должен быть ключ1, 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); 
    } 
} 

После первой итерации цикла в то время как эти пары будут напечатаны и удалены с карты:

  • key1 ааа
  • key2 SSS
  • ключ3 GGG
  • КЛЮЧ4 ааа

Во второй итерации, не будет никакого Key4 на карте и оставшийся ключ, значение пары будут напечатаны в следующем порядке:

  • key1 ГЭБ
  • key2 еее
  • ключ3 ий

Ответ @ arunpandianp дает тот же результат/вывод, но этот код немного проще.

Edit: ключ3 - ггг будет отпечатан до Key3 - ий

0

Я согласен, что Multimap не лучшая структура данных для того, что вы пытаетесь достичь; a Map из Lists может работать здесь лучше. MultiMap сортирует значения в соответствии с их естественным порядком (если не поставляется с обычным компаратором). Если я правильно понимаю, то вам нужно заказывать время вставки (игнорируя ошибку ggg в ожидаемом выходе, на что указывает @Louis Wasserman). Я не могу придумать, как добиться этого, не изменяя тип значения карты с String в пользовательский класс. Ниже приведен фрагмент ниже.

TreeMultimap представляет значения как NavigableSet, в которых не все равно случайные acces (опять же, аргумент для выбора другого контейнера) - следовательно, необходимо использовать последний кеш значений для чередующегося вывода.

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

Вы могли бы сделать больше чтобы оптимизировать его и сделать его немного умнее, но я решил сохранить его как можно более понятным и понятным.

Смежные вопросы