Sort List<Map<String,Object>> based on value

拟墨画扇 提交于 2021-01-19 09:01:26

问题


Basically I have a List<Map<String,Object>>, and I want to sort it by the values of certain key in the map.

The problem is that I do not know the type... This map can contain Strings, Integers, Doubles, Floats etc.... I would like to sort it:

So far

List<Map<String,Object>> data = getResults();
Collections.sort(data, (o1, o2) -> (String.valueOf(o2.get("Field1")))
              .compareTo((String.valueOf(o1.get("Field1")))));

It is not a great Idea since numbers are not properly sorted.... How can I handle this?


回答1:


You can generalize comparing numbers by comparing their double values, because they are the largest. If two objects cannot be cast to numbers and the double value cannot be parsed from these objects, then compare their string values:

List<Map<String, Object>> data = Arrays.asList(
        Map.of("Field1", 21.2d),  // Double
        Map.of("Field1", "qqq"),  // String
        Map.of("Field1", "22.5"), // String
        Map.of("Field1", 2),      // Integer
        Map.of("Field1", 3L),     // Long
        Map.of("Field1", 23.1f)); // Float
data.sort(Comparator.comparingDouble((Map<String, Object> map) -> {
    Object object = map.get("Field1");
    if (object instanceof Number) {
        return ((Number) object).doubleValue();
    } else {
        try {
            return Double.parseDouble(String.valueOf(object));
        } catch (NumberFormatException e) {
            return Double.NaN;
        }
    }
}).thenComparing(map -> String.valueOf(map.get("Field1"))));
data.forEach(System.out::println);
// {Field1=2}
// {Field1=3}
// {Field1=21.2}
// {Field1=22.5}
// {Field1=23.1}
// {Field1=qqq}

See also: Sort 2D List by Column Header




回答2:


First you will have to define the desired order, especially the place of the string values, or are they all numbers in text form?

Then implement a more complex comparator method, working through your comparison criteria from highest to lowest priority.

Untested:

 List<Map<String, Object>> list = new ArrayList<>();
    Collections.sort(list, (map1, map2) -> {
      Object v1 = map1.get("Field1");
      Object v2 = map2.get("Field1");

      // --------------------------------------------
      // handle null
      // --------------------------------------------
      if(v1 == null && v2 == null) {
        return 0;
      }

      if(v1 == null && v2 != null) {
        return -1 /* null value before non-null value */;
      }

      if(v1 != null && v2 == null) {
        return 1 /* non-null value after null value */;
      }

      // --------------------------------------------
      // handle String
      // --------------------------------------------
      boolean v1IsString = v1 instanceof String;
      boolean v2IsString = v2 instanceof String;
      if(v1IsString && v2IsString) {
        return ((String) v1).compareToIgnoreCase((String) v2);
      }

      if(v1IsString && !v2IsString) {
        return -1 /* string value before non-string values */;
      }

      if(!v1IsString && v2IsString) {
        return 1 /* non-string value after string value */;
      }

      // --------------------------------------------
      // handle LocalDate
      // --------------------------------------------
      // ....

      // --------------------------------------------
      // handle Instant
      // --------------------------------------------
      // ....

      // --------------------------------------------
      // handle BigDecimal and BigInteger
      // --------------------------------------------
      // ....

      // --------------------------------------------
      // handle Number
      // --------------------------------------------
      boolean v1IsNumber = v1 instanceof Number;
      boolean v2IsNumber = v2 instanceof Number;
      if(v1IsNumber && v2IsNumber) {
        double d1 = ((Number) v1).doubleValue();
        double d2 = ((Number) v2).doubleValue();
        return (int) Math.signum(d1 - d2);
      }

      if(v1IsNumber && !v2IsNumber) {
        return -1 /* number value before non-number values */;
      }

      if(!v1IsNumber && v2IsNumber) {
        return 1 /* non-number value after number value */;
      }

      // etc.

      // --------------------------------------------
      // finally, treat all unhandled value types as equal
      // --------------------------------------------
      return 0;
    });


来源:https://stackoverflow.com/questions/65310960/sort-listmapstring-object-based-on-value

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!