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
구현이 있으며,이 메소드에는 firstKey
and와 같은 메소드가 있으며 원하는 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
하여 추가 할 것이라고 생각 합니다. 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());
및 메소드 가있는 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;
}