我使用过,LinkedHashMap
因为在地图中输入键的顺序很重要。
但是现在我想获得键的值在第一个位置(第一个输入的条目)或最后一个。
是否应该有类似first()
和之last()
类的方法?
我是否需要一个迭代器才能获取第一个密钥项?那就是为什么我用过LinkedHashMap
!
谢谢!
我使用过,LinkedHashMap
因为在地图中输入键的顺序很重要。
但是现在我想获得键的值在第一个位置(第一个输入的条目)或最后一个。
是否应该有类似first()
和之last()
类的方法?
我是否需要一个迭代器才能获取第一个密钥项?那就是为什么我用过LinkedHashMap
!
谢谢!
Answers:
的语义LinkedHashMap
仍然是地图的语义,而不是的语义LinkedList
。是的,它保留插入顺序,但这只是实现细节,而不是其接口的一个方面。
获得“第一”条目的最快方法仍然是entrySet().iterator().next()
。获取“最后一个”条目是可能的,但是将需要通过调用.next()
直到到达最后一个条目来遍历整个条目集。 while (iterator.hasNext()) { lastElement = iterator.next() }
编辑:但是,如果您愿意超越JavaSE API,则Apache Commons Collections拥有自己的LinkedMap
实现,该实现具有诸如firstKey
和的方法lastKey
,它们可以满足您的需求。界面相当丰富。
mylinkedmap.entrySet().iterator().next()
吗?时间复杂度是多少?是O(1)吗?
您可以尝试做类似的事情(获取最后一个条目)吗:
linkedHashMap.entrySet().toArray()[linkedHashMap.size() -1];
T last = null ; for( T item : linkedHashMap.values() ) last = item;
或类似的东西。时间为O(N),但内存为O(1)。
我知道来得太晚了,但我想提供一些替代方法,不是非凡的选择,而是一些在此未提及的情况。如果某人不太在乎效率,但是他想要更简单的东西(也许用一行代码找到最后一个入口值),那么随着Java 8的到来,所有这些都将变得非常简单 。我提供了一些有用的方案。
为了完整起见,我将这些替代方案与其他用户已经在本文中提到的数组解决方案进行了比较。我总结了所有情况,并且我认为它们将是有用的(无论性能是否重要),对于新开发人员而言,总是取决于每个问题的问题
我从上一个答案中选择了进行以下比较。此解决方案属于@feresr。
public static String FindLasstEntryWithArrayMethod() {
return String.valueOf(linkedmap.entrySet().toArray()[linkedmap.size() - 1]);
}
与第一个解决方案相似,但性能略有不同
public static String FindLasstEntryWithArrayListMethod() {
List<Entry<Integer, String>> entryList = new ArrayList<Map.Entry<Integer, String>>(linkedmap.entrySet());
return entryList.get(entryList.size() - 1).getValue();
}
此方法将减少元素集,直到获得流的最后一个元素。此外,它将仅返回确定性结果
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();
}
来自Google Guava的Iterables.getLast。它也对列表和排序集进行了一些优化
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<Integer, String> linkedmap;
public static void main(String[] args) {
linkedmap = new LinkedHashMap<Integer, String>();
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<Entry<Integer, String>> entryList = new ArrayList<Map.Entry<Integer, String>>(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
当前的实现(Java 8)跟踪其尾巴。如果需要考虑性能和/或地图很大,则可以通过反射访问该字段。
由于实现可能会发生变化,因此最好有一个后备策略。如果引发了异常,则可能需要记录一些内容,以便您知道实现已更改。
它可能看起来像:
public static <K, V> Entry<K, V> getFirst(Map<K, V> map) {
if (map.isEmpty()) return null;
return map.entrySet().iterator().next();
}
public static <K, V> Entry<K, V> getLast(Map<K, V> map) {
try {
if (map instanceof LinkedHashMap) return getLastViaReflection(map);
} catch (Exception ignore) { }
return getLastByIterating(map);
}
private static <K, V> Entry<K, V> getLastByIterating(Map<K, V> map) {
Entry<K, V> last = null;
for (Entry<K, V> e : map.entrySet()) last = e;
return last;
}
private static <K, V> Entry<K, V> getLastViaReflection(Map<K, V> map) throws NoSuchFieldException, IllegalAccessException {
Field tail = map.getClass().getDeclaredField("tail");
tail.setAccessible(true);
return (Entry<K, V>) tail.get(map);
}
ClassCastException
到catch
万一tail
不是Entry
在子类中(或未来的实现)。
获取LinkedHashMap的第一个条目和最后一个条目的另一种方法是使用Set接口的“ toArray”方法。
但是我认为对条目集中的条目进行迭代并获得第一个和最后一个条目是更好的方法。
数组方法的使用会导致警告“ ...需要未经检查的转换以符合...”的形式,该警告无法固定[但只能通过使用注释@SuppressWarnings(“ unchecked”)来抑制]。
这是一个小示例,用于演示“ toArray”方法的用法:
public static void main(final String[] args) {
final Map<Integer,String> orderMap = new LinkedHashMap<Integer,String>();
orderMap.put(6, "Six");
orderMap.put(7, "Seven");
orderMap.put(3, "Three");
orderMap.put(100, "Hundered");
orderMap.put(10, "Ten");
final Set<Entry<Integer, String>> mapValues = orderMap.entrySet();
final int maplength = mapValues.size();
final Entry<Integer,String>[] 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
它有点脏,但是您可以重写removeEldestEntry
LinkedHashMap 的方法,它可能适合您作为私有匿名成员执行:
private Splat eldest = null;
private LinkedHashMap<Integer, Splat> pastFutures = new LinkedHashMap<Integer, Splat>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Splat> eldest) {
eldest = eldest.getValue();
return false;
}
};
因此,您将始终能够在您的eldest
会员处获得第一笔入场券。每次您执行时都会更新put
。
它也应该易于覆盖put
和设置youngest
...
@Override
public Splat put(Integer key, Splat value) {
youngest = value;
return super.put(key, value);
}
但是,当您开始删除条目时,一切都会崩溃;还没有找到一种方法去解决这个问题。
非常烦人的是,您否则无法以明智的方式使用头部或尾巴...
也许是这样的:
LinkedHashMap<Integer, String> 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;
}
建议:
map.remove(map.keySet().iterator().next());
我建议使用具有和方法的ConcurrentSkipListMapfirstKey()
lastKey()
是的,我遇到了同样的问题,但幸运的是,我只需要第一个要素...-这就是我所做的。
private String getDefaultPlayerType()
{
String defaultPlayerType = "";
for(LinkedHashMap.Entry<String,Integer> entry : getLeagueByName(currentLeague).getStatisticsOrder().entrySet())
{
defaultPlayerType = entry.getKey();
break;
}
return defaultPlayerType;
}
如果您还需要最后一个元素-我将研究如何反转地图的顺序-将其存储在temp变量中,访问反转后的地图中的第一个元素(因此它将是您的最后一个元素),请杀死临时变量。
这是一些有关如何反向排列哈希表的好答案:
如果您使用上述链接中的帮助,请给他们投票:)希望这可以对某人有所帮助。
public static List<Fragment> pullToBackStack() {
List<Fragment> fragments = new ArrayList<>();
List<Map.Entry<String, Fragment>> entryList = new ArrayList<>(backMap.entrySet());
int size = entryList.size();
if (size > 0) {
for (int i = size - 1; i >= 0; i--) {// last Fragments
fragments.add(entryList.get(i).getValue());
backMap.remove(entryList.get(i).getKey());
}
return fragments;
}
return null;
}