如何获取LinkedHashMap中每个条目的最后一个元素?

3
我有一个地图,想从中提取每个键的最后一个值,但我无法获取它:
import java.util.LinkedHashMap;
import java.util.Map;

class MyTestClass {

    private static final String almacenNombreClase = "Professor";

    private static final String TXT = "TXT";
    private static final String NUM = "NUM";

    public static void main(String[] args) {
        Map<String, Map<String, String>> mapNombreClaseYPropiedades = new LinkedHashMap<>();
        mapNombreClaseYPropiedades.put("Professor", Map.of("texto", TXT, 
                                                            "tipo", TXT, 
                                                            "prueba", NUM, 
                                                            "dificultad", NUM ));
        mapNombreClaseYPropiedades.put("Exam", Map.of("texto", TXT,
                                                      "nivel", NUM ));

        //values of mapNombreClaseYPropiedades
        Map<String, String> valores = mapNombreClaseYPropiedades.get(almacenNombreClase);

        valores.forEach((k, v) -> {
            // Here I want to check the last element of each entry
            if (v instanceof String ) {
                System.out.println("String " + k + ",");
            } else {
                System.out.println("Integer " + k + ",");
            }
        });
        // I want to see output
        "dificultad=NUM"
        "nivel=NUM"
    }
}

提取:

dificultad=NUM
nivel=NUM

即每个键的最后NUM条记录。

textotipopruebadificultadnivel是固定的吗?也就是说,您是否事先知道它们所有的内容?还是它们完全是动态的?也就是说,它们可以是任何东西。 - fps
可以是动态的或任何 @fps。 - okjfokjrf
接受的答案在技术上可以与您的代码配合使用,因为Map.of()的底层实现是保持顺序的(但接口不能保证)。但如果这是一项学校作业,我会尝试使用标准的Map接口来解决问题。您编写的方式告诉我您对涉及的数据结构不太了解。 - crig
是的,我本来想说被接受的解决方案有一个错误。你的输出表明你想要在字段映射中获取最后输入的NUM。然而,映射是无序的,因此每次执行解决方案时结果都会改变。可以使用String->List<String>来定义Prof->字段列表之间的映射,然后有一个映射将String->数据类型(String/Class)。然后可以调整已接受的解决方案以使其正常工作。 - Rob Evans
你如何获取在Map.of()中定义的最后一个值?键/值条目可能与Map.of()初始化器中出现的顺序不同。 - WJS
3个回答

2
您可以使用reduceMap<String,String>中提取最后一个值,然后使用toMap将它们收集到LinkedHashMap中以保存插入顺序。
但是请注意,为了保留顺序,您必须在输入和输出中都使用LinkedHashMap
    Map<String,String> valores = mapNombreClaseYPropiedades.values()
            .stream()
            .map(map->map.entrySet().stream().reduce((prev,next)->next))
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect(Collectors.toMap(Map.Entry::getKey,Map.Entry::getValue, (prev,next)->next,LinkedHashMap::new));

1
    Map<String, Map<String, String>> mapNombreClaseYPropiedades = new LinkedHashMap<>();
    mapNombreClaseYPropiedades.put("Professor", new LinkedHashMap<>() {{
        put("texto", "TXT");
        put("tipo", "TXT");
        put("prueba", "NUM");
        put("dificultad", "NUM");
    }});
    mapNombreClaseYPropiedades.put("Exam", new LinkedHashMap<>() {{
        put("texto", "TXT");
        put("nivel", "NUM");
    }});

    mapNombreClaseYPropiedades.values().stream()
            .map(lhm -> lhm.entrySet().stream()
                    .skip(lhm.size() - 1)
                    .findFirst()
                    .map(last -> last.getKey() + "," + last.getValue()))
            .forEach(System.out::println);

这里有一个解决方案,可以确保地图的顺序,并且它显示您可以跳过而不是减少,因为当您想要最后一个元素时,这确实是您所做的事情。

1

我建议您采取以下措施,因为简单的流无法正常工作,因为内部映射未排序,因此可能会产生不一致的结果。

  • 首先,内部映射需要是LinkedHashMap。这可以保证顺序在每次运行时不会改变。
  • 编写一个实用程序方法,就像Map.of()一样接受键,但返回一个LinkedHashMap。

现在创建地图

private static final String TXT = "TXT";
private static final String NUM = "NUM";

Map<String, Map<String, String>> mapNombreClaseYPropiedades =
            new LinkedHashMap<>();
    
mapNombreClaseYPropiedades.put("Professor", createMap(
            "texto", TXT, "tipo", TXT,
                    "prueba", NUM, "dificultad", NUM));
    
mapNombreClaseYPropiedades.put("Exam", createMap(
            "texto", TXT, "nivel", NUM));

现在只需将值流式传输并创建一个条目集列表。这是通过从已创建的列表中取出最后一个条目来实现的。由于entrySet是一个链接列表,所以它保证维护顺序。空映射会被过滤掉。
List<Entry<String,String>> last = mapNombreClaseYPropiedades.values()
            .stream().filter(s->s != null && !s.isEmpty())
            .map(m -> new ArrayList<>(m.entrySet()))
            .map(lst -> lst.get(lst.size() - 1))
            .toList(); // java 16 - or use .collect(Collectors.toList());
    
System.out.println(last);

输出
[dificultad=NUM, nivel=NUM]

这里是一个返回 LinkedHashMap 的方法。
    
private static Map<String,String> createMap(String...keyValues) {
    Map<String,String> map = new LinkedHashMap<>();
    for (int i = 0; i < keyValues.length; i+=2) {
        map.put(keyValues[i], keyValues[i+1]);
    }
    return map;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接