วิธีรับหนึ่งรายการจาก hashmap โดยไม่ต้องวนซ้ำ


172

มีวิธีหรูหราในการรับเพียงหนึ่งเดียวEntry<K,V>จาก HashMap โดยไม่ต้องวนซ้ำถ้าไม่ทราบรหัส

ลำดับการป้อนข้อมูลไม่สำคัญเราสามารถพูดได้ไหม

hashMapObject.get(zeroth_index);

แม้ว่าฉันจะรู้ว่าไม่มีวิธีการรับโดยดัชนีดังกล่าว

ถ้าฉันพยายามวิธีการที่กล่าวถึงด้านล่างก็ยังคงต้องได้รับทุกชุดการเข้ามาของ HashMap

for(Map.Entry<String, String> entry : MapObj.entrySet()) {
    return entry;
}

ข้อเสนอแนะยินดีต้อนรับ

แก้ไข: โปรดแนะนำโครงสร้างข้อมูลอื่น ๆ ให้เพียงพอ

คำตอบ:


93

คำตอบของ Jesper นั้นดี โซลูชันอื่นคือใช้ TreeMap (คุณถามโครงสร้างข้อมูลอื่น)

TreeMap<String, String> myMap = new TreeMap<String, String>();
String first = myMap.firstEntry().getValue();
String firstOther = myMap.get(myMap.firstKey());

TreeMap มีโอเวอร์เฮดเพื่อให้ HashMap เร็วขึ้น แต่เป็นเพียงตัวอย่างของโซลูชันทางเลือก


หรือ ConcurrentSkipListMap
Stephen Denne

ด้วยเหตุผลบางอย่างfirstEntry()วิธีการที่ไม่ได้กำหนดไว้ในส่วนต่อประสานSortedMapแต่เฉพาะในTreeMapและConcurrentSkipListMap:(
janko

1
firstEntry () ถูกกำหนดในอินเตอร์เฟส NavigableMap
ต่อÖstlund

อ่าขอบคุณฉันแค่ดูSortedMapเพราะมันมีfirstKey()วิธี
janko

251

ไม่มีการสั่งซื้อแผนที่ดังนั้นจึงไม่มีสิ่งใดเป็น "รายการแรก" และนั่นเป็นสาเหตุที่ไม่มีวิธีรับแบบดัชนีตามMap(หรือHashMap)

คุณสามารถทำได้:

Map<String, String> map = ...;  // wherever you get this from

// Get the first entry that the iterator returns
Map.Entry<String, String> entry = map.entrySet().iterator().next();

(หมายเหตุ: การตรวจสอบการเว้นว่างของแผนที่)

รหัสของคุณไม่ได้รับรายการทั้งหมดในแผนที่จะส่งคืนทันที (และแยกออกจากลูป) ด้วยรายการแรกที่พบ

หากต้องการพิมพ์คีย์และค่าขององค์ประกอบแรกนี้:

System.out.println("Key: "+entry.getKey()+", Value: "+entry.getValue());

หมายเหตุ: การโทรiterator()ไม่ได้หมายความว่าคุณกำลังวนซ้ำแผนที่ทั้งหมด


3
เพียงแค่บันทึกด้านข้าง: LinkedHashMapเก็บกุญแจไว้ในลำดับที่ถูกใส่เข้าไป
Matthieu

2
ใช่แผนที่โดยทั่วไปจะไม่ได้รับคำสั่ง แต่Mapการใช้งานบางอย่างเช่นLinkedHashMapและTreeMapมีคำสั่งที่กำหนดไว้ ( HashMapไม่)
Jesper

1
คำตอบที่ดีกว่าคำตอบที่เลือก - เนื่องจากคำตอบที่เลือกใช้ TreeMap ซึ่งคาดว่ากุญแจจะเป็นประเภทที่เปรียบเทียบได้
Yazad

28

ฉันเดาว่าตัววนซ้ำอาจเป็นวิธีที่ง่ายที่สุด

return hashMapObject.entrySet().iterator().next();

วิธีแก้ปัญหาอื่น (ไม่สวย):

return new ArrayList(hashMapObject.entrySet()).get(0);

หรือยัง (ไม่ดีกว่า):

return hashMapObject.entrySet().toArray()[0];

7
ไม่มีเหตุผลที่จะใช้รุ่นที่สองหรือสาม คนแรกดีอย่างสมบูรณ์อีกสองคนเสียเวลามากโดยให้อาร์เรย์ / รายการเพื่ออะไร
Joachim Sauer

4
ผมเห็นด้วยจึง "ไม่สวย" ความคิดเห็น ;-)
cadrian

14

รับค่าแปลงเป็นอาร์เรย์รับองค์ประกอบแรกของอาร์เรย์:

map.values().toArray()[0]

ดับบลิว


8

ทำไมคุณต้องการหลีกเลี่ยงการโทรentrySet()มันไม่ได้สร้างวัตถุใหม่ทั้งหมดที่มีบริบทของตัวเอง แต่แทนที่จะให้วัตถุซุ้ม การพูดง่าย ๆentrySet()คือการดำเนินการที่ค่อนข้างถูก



6

หากคุณต้องการ API ที่คุณแนะนำจริงๆคุณสามารถ subclass HashMap และติดตามคีย์ในรายการตัวอย่าง ไม่เห็นจุดนี้จริงๆ แต่ให้สิ่งที่คุณต้องการ หากคุณอธิบายกรณีการใช้งานที่ตั้งใจไว้เราอาจคิดวิธีแก้ปัญหาที่ดีกว่า

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@SuppressWarnings("unchecked")
public class IndexedMap extends HashMap {

    private List<Object> keyIndex;

    public IndexedMap() {
        keyIndex = new ArrayList<Object>();
    }

    /**
     * Returns the key at the specified position in this Map's keyIndex.
     * 
     * @param index
     *            index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException
     *             if the index is out of range (index < 0 || index >= size())
     */
    public Object get(int index) {
        return keyIndex.get(index);
    }

    @Override
    public Object put(Object key, Object value) {

        addKeyToIndex(key);
        return super.put(key, value);
    }

    @Override
    public void putAll(Map source) {

        for (Object key : source.keySet()) {
            addKeyToIndex(key);
        }
        super.putAll(source);
    }

    private void addKeyToIndex(Object key) {

        if (!keyIndex.contains(key)) {
            keyIndex.add(key);
        }
    }

    @Override
    public Object remove(Object key) {

        keyIndex.remove(key);
        return super.remove(key);
    }
}

แก้ไข: ฉันจงใจไม่ได้เจาะลึกด้าน generics ของนี้ ...


4

คุณหมายความว่าอย่างไรกับ "ไม่ทำซ้ำ"

คุณสามารถใช้map.entrySet().iterator().next()และคุณจะไม่ทำซ้ำผ่านแผนที่ (ในความหมายของ "การสัมผัสแต่ละวัตถุ") คุณไม่สามารถระงับได้Entry<K, V>โดยไม่ต้องใช้ตัววนซ้ำ Javadoc ของMap.Entryพูดว่า:

วิธีการ Map.entrySet ส่งกลับมุมมองคอลเลกชันของแผนที่ซึ่งองค์ประกอบอยู่ในระดับนี้ วิธีเดียวที่จะได้รับการอ้างอิงไปยังรายการแผนที่นั้นมาจากตัววนซ้ำของมุมมองคอลเลกชันนี้ วัตถุ Map.Entry เหล่านี้ใช้ได้เฉพาะในช่วงระยะเวลาของการวนซ้ำเท่านั้น

คุณช่วยอธิบายรายละเอียดเพิ่มเติมสิ่งที่คุณกำลังพยายามทำให้สำเร็จ หากคุณต้องการที่จะจับวัตถุแรกที่ตรงกับเกณฑ์ที่เฉพาะเจาะจง (เช่น "มีความสำคัญโดยเฉพาะอย่างยิ่ง") และถอยกลับไปยังวัตถุที่เหลือมิฉะนั้นแล้วมองไปที่แถวคอยลำดับความสำคัญ มันจะสั่งวัตถุของคุณตามลำดับธรรมชาติหรือกำหนดเองComparatorที่คุณให้


4
import java.util.*;

public class Friday {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("code", 10);
        map.put("to", 11);
        map.put("joy", 12);

        if (! map.isEmpty()) {
            Map.Entry<String, Integer> entry = map.entrySet().iterator().next();
            System.out.println(entry);
        }
    }
}

วิธีการนี้ใช้ไม่ได้เพราะคุณใช้ HashMap ฉันคิดว่าการใช้ LinkedHashMap จะเป็นทางออกที่ถูกต้องในกรณีนี้


1
มีวิธีใดในLinkedHashMapที่ทำให้ LinkedHashmap ทำงานได้ซึ่งรหัสนี้ไม่ได้?
SL Barth - Reinstate Monica

3

สิ่งนี้จะได้รับรายการเดียวจากแผนที่ซึ่งใกล้เคียงที่สุดที่จะได้รับเนื่องจาก 'แรก' ไม่ได้ใช้จริง ๆ

import java.util.*;

public class Friday {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("code", 10);
        map.put("to", 11);
        map.put("joy", 12);

        if (! map.isEmpty()) {
            Map.Entry<String, Integer> entry = map.entrySet().iterator().next();
            System.out.println(entry);
        }
    }
}

2

สะดุดที่นี่เพื่อมองหาสิ่งเดียวกัน ... จากนั้นฉันจำIterablesชั้นเรียนได้จากห้องสมุด Guavaห้องสมุดฝรั่ง

ที่จะได้รับ "ครั้งแรก" Iterables.getFirst( someMap.values(), null );องค์ประกอบ:
เป็นหลักทำเช่นเดียวกันMap.values().iterator().next()แต่ยังช่วยให้คุณสามารถระบุค่าเริ่มต้น (ในกรณีนี้เป็นโมฆะ) หากไม่มีสิ่งใดในแผนที่

Iterables.getLast( someMap.values(), null ); ส่งคืนองค์ประกอบสุดท้ายในแผนที่

Iterables.get( someMap.values(), 7, null ); ส่งคืนองค์ประกอบที่ 7 ในแผนที่หากมีอยู่มิฉะนั้นจะเป็นค่าเริ่มต้น (ในกรณีนี้จะเป็นโมฆะ)

จำไว้ว่า HashMaps ที่ไม่ได้รับคำสั่ง ... จึงไม่คาดหวังIterables.getFirstที่จะกลับรายการแรกที่คุณโยนในมี ... Iterables.getLastเช่นเดียวกันกับ ประโยชน์ที่จะได้รับบางทีค่าแมปว่า

มันอาจจะไม่คุ้มที่จะเพิ่มห้องสมุด Guava เพียงแค่นั้น แต่ถ้าคุณใช้ยูทิลิตี้ที่ยอดเยี่ยมอื่น ๆ ภายในห้องสมุดนั้น ...


1

ติดตามการแก้ไขของคุณต่อไปนี้เป็นคำแนะนำของฉัน:

หากคุณมีเพียงรายการเดียวคุณอาจแทนที่แผนที่ด้วยวัตถุคู่ ขึ้นอยู่กับประเภทและความชอบของคุณ:

  • อาร์เรย์ (ของ 2 ค่าคีย์และค่า)
  • วัตถุอย่างง่ายที่มีคุณสมบัติสองอย่าง

0
map<string,string>m;
auto it=m.begin();//get iterator to the first element of map(m)
return m->first;//return first string(1st string in map<string,string>m)
//Incase you want the second string 
//you can use return m->second(2st string in map<string,string>m)
//if you want to iterate the whole map you can use loop
for(auto it:m)//m is a map
   cout<<it->first<<endl;

4
ในขณะที่รหัสนี้อาจตอบคำถาม แต่มีบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีการที่รหัสนี้ตอบคำถามช่วยปรับปรุงมูลค่าระยะยาว
Alex Riabov

1
ใช่โปรดเพิ่มคำอธิบายพร้อมกับรหัสของคุณ
jkdev

-3

ฉันได้รับคำตอบ: (มันง่าย)

ใช้ ArrayList จากนั้นส่งและค้นหาขนาดของ arraylist นี่มันคือ:

    ArrayList count = new ArrayList();
    count=(ArrayList) maptabcolname.get("k1"); //here "k1" is Key
    System.out.println("number of elements="+count.size());

มันจะแสดงขนาด (ให้คำแนะนำ) มันใช้งานได้ดี


2
สิ่งนี้จะได้รับหนึ่งรายการโดยพลการจากแผนที่แฮชหรือไม่
พันเอกสามสิบสอง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.