วิธีที่มีประสิทธิภาพในการวนซ้ำและคัดลอกค่าของ HashMap


9

ฉันต้องการแปลง:

Map<String, Map<String, List<Map<String, String>>>> inputMap 

ถึง:

Map<String, Map<String, CustomObject>> customMap

inputMapมีให้ในการกำหนดค่าและพร้อม แต่ฉันต้องการcustomMapจัดรูปแบบ CustomObject จะได้มาจากการList<Map<String, String>>ใช้โค้ดไม่กี่บรรทัดในฟังก์ชั่น

ฉันได้ลองวิธีการทำแผนที่อินพุตซ้ำและคัดลอกค่าคีย์ใน customMap แล้ว มีวิธีที่มีประสิทธิภาพในการทำเช่นนั้นโดยใช้ Java 8 หรือทางลัดอื่น ๆ ?

Map<String, Map<String, List<Map<String, String>>>> configuredMap = new HashMap<>();
Map<String, Map<String, CustomObj>> finalMap = new HashMap<>();


for (Map.Entry<String, Map<String, List<Map<String, String>>>> attributeEntry : configuredMap.entrySet()) {
    Map<String, CustomObj> innerMap = new HashMap<>();
    for (Map.Entry<String, List<Map<String, String>>> valueEntry : attributeEntry.getValue().entrySet()) {
        innerMap.put(valueEntry.getKey(), getCustomeObj(valueEntry.getValue()));
    }
    finalMap.put(attributeEntry.getKey(), innerMap);
}

private CustomObj getCustomeObj(List<Map<String, String>> list) {
    return new CustomObj();
}

โปรดจัดรูปแบบรหัสให้ถูกต้อง
akuzminykh

1
คุณคิดจะสร้างส่วนหน้าแทนที่จะคัดลอกหรือไม่?
ControlAltDel

ไม่มีวิธีใดที่มีประสิทธิภาพมากกว่านี้อีกแล้ว การดำเนินการทั้งหมดนั้นต้องเกิดขึ้น แต่รหัสนี้ใช้งานไม่ได้จริง คุณไม่ได้ใส่รายการลงในวัตถุที่กำหนดเอง
user207421

คำตอบ:


2

ทางออกหนึ่งคือการสตรีมentrySetจากinputMapแล้วใช้Collectors#toMapสองครั้ง (หนึ่งครั้งสำหรับด้านนอกMapและอีกครั้งสำหรับด้านในMap):

Map<String, Map<String, CustomObj>> customMap = inputMap.entrySet()
        .stream()
        .collect(Collectors.toMap(Function.identity(), entry -> {
            return entry.getValue()
                        .entrySet()
                        .stream()
                        .collect(Collectors.toMap(Function.identity(), 
                            entry -> getCustomeObj(entry.getValue())));
        }));

คุณสามารถละเว้น{}และข้อความสั่งคืนในแลมบ์ดาได้บางสิ่งดังนี้:.collect(Collectors.toMap(Function.identity(), entry -> entry.getValue() .entrySet() .stream() .collect(Collectors.toMap(Function.identity(), entry -> getCustomeObj(entry.getValue()))); ));
โชโก

3
@Shooko จริง แต่ฉันคิดว่ามันจะดูน้อยอ่านได้โดยไม่ต้องบล็อก
Jacob G.

1

คุณสามารถสตรีมได้ แต่นั่นจะดูไม่สามารถอ่านได้ อย่างน้อยสำหรับฉัน ดังนั้นหากคุณมีวิธีการ:

static CustomObject fun(List<Map<String, String>> in) {
    return .... // whatever processing you have here
}

คุณยังคงสามารถใช้java-8ไวยากรณ์ได้ แต่ในรูปแบบอื่น:

    Map<String, Map<String, CustomObject>> customMap = new HashMap<>();

    inputMap.forEach((key, value) -> {

        value.forEach((innerKey, listOfMaps) -> {

            Map<String, CustomObject> innerMap = new HashMap<>();
            innerMap.put(innerKey, fun(listOfMaps));
            customMap.put(key, innerMap);

        });
    });

หากคุณสามารถสร้างแผนที่ด้านในได้คุณสามารถทำให้แผนที่immutableสั้นลงได้:

inputMap.forEach((key, value) -> {
      value.forEach((innerKey, listOfMaps) -> {
          customMap.put(key, Collections.singletonMap(innerKey, fun(listOfMaps)));
      });
});

1

การสตรีม IMHO นั้นไม่ใช่ความคิดที่เลวร้ายนัก ไม่มีเครื่องมือที่ไม่ดี ขึ้นอยู่กับว่าคุณใช้งานอย่างไร


ในกรณีพิเศษนี้ฉันจะแยกรูปแบบการทำซ้ำลงในวิธีการยูทิลิตี้:

public static <K, V1, V2> Map<K, V2> transformValues(Map<K, V1> map, Function<V1, V2> transformer) {
    return map.entrySet()
              .stream()
              .collect(toMap(Entry::getKey, e -> transformer.apply(e.getValue())));
}

วิธีการข้างต้นสามารถดำเนินการได้โดยใช้วิธีการใด ๆ แม้ว่าฉันคิดว่าStream APIเหมาะสมดีที่นี่


เมื่อคุณกำหนดวิธีการยูทิลิตี้มันสามารถใช้ง่ายดังต่อไปนี้:

Map<String, Map<String, CustomObj>> customMap = 
    transformValues(inputMap, attr -> transformValues(attr, this::getCustomObj));

การเปลี่ยนแปลงที่แท้จริงคือหนึ่งซับได้อย่างมีประสิทธิภาพ ดังนั้นด้วยความที่เหมาะสมJavaDocสำหรับtransformValuesวิธีการรหัสผลที่ได้คือสวยอ่านและการบำรุงรักษา


1

วิธีการเกี่ยวกับCollectors.toMapรายการทั้งในระดับนอกและภายในเช่น:

Map<String, Map<String, CustomObj>> finalMap = configuredMap.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                attributeEntry -> attributeEntry.getValue().entrySet()
                        .stream()
                        .collect(Collectors.toMap(Map.Entry::getKey,
                                valueEntry -> getCustomeObj(valueEntry.getValue())))));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.