LinkedHashMap지도에 키를 입력 한 순서가 중요하기 때문에 사용 했습니다.
그러나 이제 첫 번째 (첫 번째 입력 한 항목) 또는 마지막에서 키의 가치를 얻고 싶습니다.
유사한 방법이 있어야 first()하고 last()그런이나 뭐?
첫 번째 키 항목을 얻으려면 반복자가 필요합니까? 그래서 내가 사용한 이유입니다 LinkedHashMap!
감사!
LinkedHashMap지도에 키를 입력 한 순서가 중요하기 때문에 사용 했습니다.
그러나 이제 첫 번째 (첫 번째 입력 한 항목) 또는 마지막에서 키의 가치를 얻고 싶습니다.
유사한 방법이 있어야 first()하고 last()그런이나 뭐?
첫 번째 키 항목을 얻으려면 반복자가 필요합니까? 그래서 내가 사용한 이유입니다 LinkedHashMap!
감사!
답변:
의 의미 LinkedHashMap는 여전히 의 의미가 아니라지도 의 의미입니다 LinkedList. 삽입 순서는 유지되지만 인터페이스의 측면이 아니라 구현 세부 사항입니다.
"첫 번째"항목을 얻는 가장 빠른 방법은 여전히 entrySet().iterator().next()입니다. "마지막"항목을 얻는 것은 가능하지만 마지막 항목에 .next()도달 할 때까지 전화를 걸어 전체 항목 세트를 반복 해야합니다. while (iterator.hasNext()) { lastElement = iterator.next() }
편집 : 그러나 JavaSE API를 넘어서고 싶다면 Apache Commons Collections 에는 자체 LinkedMap구현이 있으며,이 메소드에는 firstKeyand와 같은 메소드가 있으며 원하는 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 구아바에서 Iterables.getLast. Lists 및 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<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현재 구현 (자바 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하여 추가 할 것이라고 생각 합니다. catchtailEntry
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());
및 메소드 가있는 ConcurrentSkipListMap 을 사용 하는 것이 좋습니다.firstKey()lastKey()
linkedHashMap은 첫 번째, 마지막 또는 특정 객체를 얻는 방법을 제공하지 않습니다.
그러나 얻는 것이 아주 사소합니다.
이제 모든 객체에서 반복자를 사용합니다. 당신은 어떤 물건을 얻을 수 있습니다.
그래도 같은 문제가 발생했지만 운 좋게도 첫 번째 요소 만 필요합니다 ...-이것이 내가 한 일입니다.
private String getDefaultPlayerType()
{
String defaultPlayerType = "";
for(LinkedHashMap.Entry<String,Integer> entry : getLeagueByName(currentLeague).getStatisticsOrder().entrySet())
{
defaultPlayerType = entry.getKey();
break;
}
return defaultPlayerType;
}
마지막 요소도 필요한 경우-맵의 순서를 바꾸는 방법을 살펴보고 임시 변수에 저장하고 반전 된 맵의 첫 번째 요소에 액세스하십시오 (따라서 마지막 요소가됩니다). 임시 변수.
다음은 해시 맵을 역순으로 만드는 방법에 대한 좋은 답변입니다.
위 링크의 도움말을 사용하는 경우 투표를 해주세요. :) 이것이 누군가를 도울 수 있기를 바랍니다.
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;
}