Cách hiệu quả để lặp lại và sao chép các giá trị của HashMap


9

Tôi muốn chuyển đổi:

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

đến:

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

inputMap được cung cấp trong cấu hình và sẵn sàng nhưng tôi cần customMap Định dạng. CustomObject sẽ được bắt nguồn từ List<Map<String, String>>việc sử dụng một vài dòng mã trong một hàm.

Tôi đã thử một cách thông thường để lặp lại bản đồ đầu vào và sao chép các giá trị chính trong customMap. Có cách nào hiệu quả để làm điều đó bằng cách sử dụng Java 8 hoặc một số phím tắt khác không?

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();
}

Vui lòng định dạng mã đúng.
akuzminykh

1
Bạn đã nghĩ về việc tạo ra một mặt tiền, thay vì sao chép?
ControlAltDel

Không thể có cách nào hiệu quả hơn. Tất cả những hoạt động phải diễn ra. Nhưng mã này không thực sự hoạt động. Bạn không đưa danh sách vào đối tượng tùy chỉnh.
dùng207421

Câu trả lời:


2

Một giải pháp là để dòng entrySetcủa inputMap, và sau đó sử dụngCollectors#toMap hai lần (một lần cho bên ngoài Map, và một lần cho khu vực nội 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())));
        }));

Bạn có thể bỏ qua {}và tuyên bố trở lại trong lambda, đại loại như thế này:.collect(Collectors.toMap(Function.identity(), entry -> entry.getValue() .entrySet() .stream() .collect(Collectors.toMap(Function.identity(), entry -> getCustomeObj(entry.getValue()))); ));
SHoko

3
@SHoko Đúng, nhưng tôi nghĩ nó sẽ ít đọc hơn nếu không có khối.
Jacob G.

1

Bạn có thể truyền phát, nhưng điều đó sẽ không thể đọc được; ít nhất cho tôi. Vì vậy, nếu bạn có một phương pháp:

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

bạn vẫn có thể sử dụng java-8 cú pháp, nhưng ở dạng khác:

    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);

        });
    });

Nếu bạn có thể tạo bản đồ bên trong immutable, bạn có thể làm cho nó ngắn hơn nữa:

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

1

Truyền phát IMHO không phải là ý tưởng quá tệ. Không có công cụ xấu. Nó phụ thuộc vào cách bạn sử dụng chúng.


Trong trường hợp cụ thể này, tôi sẽ trích xuất mẫu lặp lại thành một phương thức tiện ích:

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())));
}

Phương pháp trên có thể được thực hiện bằng bất kỳ phương pháp nào, mặc dù tôi nghĩ Stream API khá phù hợp ở đây.


Khi bạn đã xác định phương thức tiện ích, nó có thể được sử dụng đơn giản như sau:

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

Việc chuyển đổi thực tế có hiệu quả một lớp lót. Vì vậy, với thích hợp JavaDoccho transformValuesphương pháp mã kết quả là khá dễ đọc và dễ bảo trì.


1

Làm thế nào về Collectors.toMapcác mục cả ở cấp độ bên ngoài và bên trong, chẳng hạn như:

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())))));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.