Java LinkedHashMap получает первую или последнюю запись

Я использовал LinkedHashMap потому что важно порядок, в котором ключи введены на карту.

Но теперь я хочу получить значение ключа в первую очередь (первая введенная запись) или последняя.

Должен ли быть метод вроде first() и last() или что-то в этом роде?

Нужно ли иметь iterator, чтобы просто получить первую ключевую запись? Вот почему я использовал LinkedHashMap !

Благодаря!

    Семантика LinkedHashMap по-прежнему относится к карте, а не к LinkedList . Он сохраняет порядок вставки, да, но это детализация реализации, а не аспект его интерфейса.

    Самый быстрый способ получить «первую» запись – это entrySet().iterator().next() . Получение «последней» записи возможно, но повлечет за собой повторение всей записи, .next() вызовом .next() пока вы не достигнете последнего. while (iterator.hasNext()) { lastElement = iterator.next() }

    edit : Однако, если вы готовы выйти за frameworks API JavaSE, Apache Commons Collections имеет свою собственную реализацию LinkedMap , которая имеет методы, такие как firstKey и lastKey , которые делают то, что вы ищете. Интерфейс значительно богаче.

    Можете ли вы попробовать что-то сделать (чтобы получить последнюю запись):

     linkedHashMap.entrySet().toArray()[linkedHashMap.size() -1]; 

    это O (N) 🙂

    Текущая реализация LinkedHashMap (Java 8) отслеживает ее хвост. Если производительность является проблемой и / или большая карта имеет размер, вы можете получить доступ к этому полю посредством отражения.

    Поскольку реализация может измениться, вероятно, неплохо иметь и резервную страtagsю. Возможно, вы захотите зарегистрировать что-то, если выбрано исключение, чтобы вы знали, что реализация изменилась.

    Это может выглядеть так:

     public static  Entry getFirst(Map map) { if (map.isEmpty()) return null; return map.entrySet().iterator().next(); } public static  Entry getLast(Map map) { try { if (map instanceof LinkedHashMap) return getLastViaReflection(map); } catch (Exception ignore) { } return getLastByIterating(map); } private static  Entry getLastByIterating(Map map) { Entry last = null; for (Entry e : map.entrySet()) last = e; return last; } private static  Entry getLastViaReflection(Map map) throws NoSuchFieldException, IllegalAccessException { Field tail = map.getClass().getDeclaredField("tail"); tail.setAccessible(true); return (Entry) tail.get(map); } 

    Еще один способ получить первую и последнюю запись LinkedHashMap – использовать метод toArray для интерфейса Set.

    Но я думаю, что повторение записей в наборе записей и получение первой и последней записи – лучший подход.

    Использование методов массива приводит к предупреждению о форме «… требуется немедленное преобразование для соответствия …», которое не может быть исправлено [но может быть подавлено только с помощью annotations @SuppressWarnings («unchecked»)].

    Вот небольшой пример, демонстрирующий использование метода toArray:

     public static void main(final String[] args) { final Map orderMap = new LinkedHashMap(); orderMap.put(6, "Six"); orderMap.put(7, "Seven"); orderMap.put(3, "Three"); orderMap.put(100, "Hundered"); orderMap.put(10, "Ten"); final Set> mapValues = orderMap.entrySet(); final int maplength = mapValues.size(); final Entry[] test = new Entry[maplength]; mapValues.toArray(test); System.out.print("First Key:"+test[0].getKey()); System.out.println(" First Value:"+test[0].getValue()); System.out.print("Last Key:"+test[maplength-1].getKey()); System.out.println(" Last Value:"+test[maplength-1].getValue()); } // the output geneated is : First Key:6 First Value:Six Last Key:10 Last Value:Ten 

    Я знаю, что я пришел слишком поздно, но я хотел бы предложить некоторые альтернативы, а не что-то необычное, но некоторые случаи, о которых никто не упоминал. В случае, если кому-то наплевать на эффективность, но он хочет что-то с большей простотой (возможно, найти последнее значение записи с одной строкой кода), все это упростится с появлением Java 8 . Я предоставляю некоторые полезные сценарии.

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

    Возможные альтернативы

    Использование метода массива

    Я взял это из предыдущего ответа, чтобы сделать последующие сравнения. Это решение принадлежит @feresr.

      public static String FindLasstEntryWithArrayMethod() { return String.valueOf(linkedmap.entrySet().toArray()[linkedmap.size() - 1]); } 

    Использование метода ArrayList

    Подобно первому решению с немного отличающейся производительностью

     public static String FindLasstEntryWithArrayListMethod() { List> entryList = new ArrayList>(linkedmap.entrySet()); return entryList.get(entryList.size() - 1).getValue(); } 

    Метод уменьшения

    Этот метод уменьшит набор элементов до получения последнего элемента streamа. Кроме того, он вернет только детерминированные результаты

     public static String FindLasstEntryWithReduceMethod() { return linkedmap.entrySet().stream().reduce((first, second) -> second).orElse(null).getValue(); } 

    Метод SkipFunction

    Этот метод получит последний элемент streamа, просто пропустив все элементы перед ним

     public static String FindLasstEntryWithSkipFunctionMethod() { final long count = linkedmap.entrySet().stream().count(); return linkedmap.entrySet().stream().skip(count - 1).findFirst().get().getValue(); } 

    Итеративная альтернатива

    Iterables.getLast из Google Guava. Он также имеет некоторую оптимизацию для списков и SortedSets

     public static String FindLasstEntryWithGuavaIterable() { return Iterables.getLast(linkedmap.entrySet()).getValue(); } 

    Вот полный исходный код

     import com.google.common.collect.Iterables; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class PerformanceTest { private static long startTime; private static long endTime; private static LinkedHashMap linkedmap; public static void main(String[] args) { linkedmap = new LinkedHashMap(); linkedmap.put(12, "Chaitanya"); linkedmap.put(2, "Rahul"); linkedmap.put(7, "Singh"); linkedmap.put(49, "Ajeet"); linkedmap.put(76, "Anuj"); //call a useless action so that the caching occurs before the jobs starts. linkedmap.entrySet().forEach(x -> {}); startTime = System.nanoTime(); FindLasstEntryWithArrayListMethod(); endTime = System.nanoTime(); System.out.println("FindLasstEntryWithArrayListMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds"); startTime = System.nanoTime(); FindLasstEntryWithArrayMethod(); endTime = System.nanoTime(); System.out.println("FindLasstEntryWithArrayMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds"); startTime = System.nanoTime(); FindLasstEntryWithReduceMethod(); endTime = System.nanoTime(); System.out.println("FindLasstEntryWithReduceMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds"); startTime = System.nanoTime(); FindLasstEntryWithSkipFunctionMethod(); endTime = System.nanoTime(); System.out.println("FindLasstEntryWithSkipFunctionMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds"); startTime = System.currentTimeMillis(); FindLasstEntryWithGuavaIterable(); endTime = System.currentTimeMillis(); System.out.println("FindLasstEntryWithGuavaIterable : " + "took " + (endTime - startTime) + " milliseconds"); } public static String FindLasstEntryWithReduceMethod() { return linkedmap.entrySet().stream().reduce((first, second) -> second).orElse(null).getValue(); } public static String FindLasstEntryWithSkipFunctionMethod() { final long count = linkedmap.entrySet().stream().count(); return linkedmap.entrySet().stream().skip(count - 1).findFirst().get().getValue(); } public static String FindLasstEntryWithGuavaIterable() { return Iterables.getLast(linkedmap.entrySet()).getValue(); } public static String FindLasstEntryWithArrayListMethod() { List> entryList = new ArrayList>(linkedmap.entrySet()); return entryList.get(entryList.size() - 1).getValue(); } public static String FindLasstEntryWithArrayMethod() { return String.valueOf(linkedmap.entrySet().toArray()[linkedmap.size() - 1]); } } 

    Вот результат с результатами каждого метода

     FindLasstEntryWithArrayListMethod : took 0.162 milliseconds FindLasstEntryWithArrayMethod : took 0.025 milliseconds FindLasstEntryWithReduceMethod : took 2.776 milliseconds FindLasstEntryWithSkipFunctionMethod : took 3.396 milliseconds FindLasstEntryWithGuavaIterable : took 11 milliseconds 

    Возможно, что-то вроде этого:

     LinkedHashMap myMap; public String getFirstKey() { String out = null; for (int key : myMap.keySet()) { out = myMap.get(key); break; } return out; } public String getLastKey() { String out = null; for (int key : myMap.keySet()) { out = myMap.get(key); } return out; } 

    Это немного грязно, но вы можете переопределить метод removeEldestEntry , который может вам подойдет как частный анонимный член:

     private Splat eldest = null; private LinkedHashMap pastFutures = new LinkedHashMap() { @Override protected boolean removeEldestEntry(Map.Entry eldest) { eldest = eldest.getValue(); return false; } }; 

    Таким образом, вы всегда сможете получить первую запись у своего eldest члена. Он будет обновляться каждый раз, когда вы выполняете put .

    Также должно быть легко переопределить и установить youngest

      @Override public Splat put(Integer key, Splat value) { youngest = value; return super.put(key, value); } 

    Все это ломается, когда вы начинаете удалять записи; не выяснили, как это сделать.

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

    Я бы рекомендовал использовать ConcurrentSkipListMap, который имеет firstKey() и lastKey()

    Предложение:

     map.remove(map.keySet().iterator().next()); 

    Хотя linkedHashMap не предоставляет никакого способа получить первый, последний или какой-либо конкретный объект.

    Но его довольно тривиально:

    • Карта orderMap = new LinkedHashMap ();
      Установите al = orderMap.keySet ();

    теперь используя iterator на любом объекте; вы можете получить любой объект.

    Да, я столкнулся с той же проблемой, но, к счастью, мне нужен только первый элемент … – Это то, что я сделал для этого.

     private String getDefaultPlayerType() { String defaultPlayerType = ""; for(LinkedHashMap.Entry entry : getLeagueByName(currentLeague).getStatisticsOrder().entrySet()) { defaultPlayerType = entry.getKey(); break; } return defaultPlayerType; } 

    Если вам нужен и последний элемент – я бы посмотрел, как изменить порядок вашей карты – сохраните его в переменной temp, получите доступ к первому элементу на карте с обратным отображением (следовательно, это будет ваш последний элемент), убейте временная переменная.

    Вот несколько хороших ответов о том, как изменить порядок hash-карт:

    Как перебрать hashmap в обратном порядке в Java

    Если вы используете помощь из приведенной выше ссылки, пожалуйста, отдайте их на голосование 🙂 Надеюсь, это может помочь кому-то.

    правильно, вам нужно вручную перечислить набор ключей до конца связанного списка, а затем получить запись по ключу и вернуть эту запись.

    Давайте будем гением компьютера.