Если вы знаете, что ваши данные не будут превышать объем вашей памяти, когда вы все прочитаете в памяти, тогда решение будет простым - с использованием LinkedList
или a и LinkedHashMap
.
Например, если вы используете Связанный список:
LinkedList<String> input = new LinkedList();
Вы затем продолжайте использовать input.add()
как вы сделали первоначально. Но когда список ввода заполнен, вы в основном используете решение Jordi Castilla, но помещаете записи в связанный список в обратном порядке. Чтобы сделать это, вы делаете:
Iterator<String> iter = list.descendingIterator();
LinkedHashMap<String,Integer> map = new LinkedHashMap<>();
while (iter.hasNext()) {
String s = iter.next();
if (map.containsKey(s)) {
map.put(s, map.get(s) + 1);
} else {
map.put(s, 1);
}
}
Теперь, единственное реальное различие между его решением и моим в том, что я использую list.descendingIterator()
, который является методом LinkedList
, который дает вам запись в обратном порядке, от «лошадей "на" кошку ".
LinkedHashMap
будет содержать правильный порядок - все, что было введено первым, будет напечатано первым, и поскольку мы ввели вещи в обратном порядке, то все, что было прочитано последним, будет напечатано первым. Так что, если вы печатаете ваш map
результат будет:
{horse=1, cat=2, dog=4, fish=2}
Если у вас есть очень длинный файл, и вы не можете загрузить весь список строк в память, вам лучше держать только карту частот. В этом случае для того, чтобы сохранить порядок записи, мы будем использовать объект, например, следующим образом:
private static class Entry implements Comparable<Entry> {
private static long nextOrder = Long.MIN_VALUE;
private String str;
private int frequency = 1;
private long order = nextOrder++;
public Entry(String str) {
this.str = str;
}
public String getString() {
return str;
}
public int getFrequency() {
return frequency;
}
public void updateEntry() {
frequency++;
order = nextOrder++;
}
@Override
public int compareTo(Entry e) {
if (order > e.order)
return -1;
if (order < e.order)
return 1;
return 0;
}
@Override
public String toString() {
return String.format("%s: %d", str, frequency);
}
}
Хитрость здесь в том, что каждый раз, когда вы обновляете запись (добавьте к частоте), его также обновляет заказ.Но метод compareTo()
заказывает Entry
объекты из высокий заказ (обновлен/вставлен позже) до низкий заказ (обновлен/вставлен ранее).
Теперь вы можете использовать простой HashMap<String,Entry>
для хранения информации, как вы читаете это (я предполагаю, что вы читаете с каким-то сканером):
Map<String,Entry> m = new HashMap<>();
while (scanner.hasNextLine()) {
String str = scanner.nextLine();
Entry entry = m.get(str);
if (entry == null) {
entry = new Entry(str);
m.put(str, entry);
} else {
entry.updateEntry();
}
}
Scanner.close();
Теперь вы можете сортировать значение записей :
List<Entry> orderedList = new ArrayList<Entry>(m.values());
m = null;
Collections.sort(orderedList);
Запуск System.out.println(orderedList)
даст вам:
[horse: 1, cat: 2, dog: 4, fish: 2]
В принципе, вы могли бы использовать TreeMap
, чьи ключи содержали «заказ», а не простой HashMap
, подобный этому, за которым следует сортировка, но я предпочитаю не иметь ни изменяемых ключей на карте, ни постоянно менять ключи. Здесь мы меняем только значения, когда мы заполняем карту, и каждый ключ вводится в карту только один раз.
сделать 'TreeMap', который будет лучшим решением, как я могу думать. –
Prashant
«TreeMap» будет заказывать строковыми клавишами, а не последним. – RealSkeptic
@RealSkeptic, я думаю, ему нужен ручной заказ по-своему. и я понял, что это не может быть TreeMap – Prashant