【问题标题】:Compare Lists in ArrayList比较 ArrayList 中的列表
【发布时间】:2018-08-30 16:02:12
【问题描述】:

我有一个包含以下字符串的文本文件(它们是软件的版本):

1_10_2_0_154
3_10_5_2_10
2_10_4_1
3_10_5_1_37

我正在尝试查找最新版本,在本例中 3_10_5_2_10 是我尝试使用 java 显示的版本。

目前,这是我的代码:

    BufferedReader br;
    String version;
    ArrayList<List<Integer>> array = new ArrayList<List<Integer>>();
    List<Integer> liste = new ArrayList<Integer>();

    try{
        br = new BufferedReader(new FileReader(new File(FILEPATH)));

        while((version= br.readLine()) != null)
        {
            liste = Arrays.asList(version.split("_")).stream().

    map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());

            array.add(liste);
        }

        for(int i = 0; i < array.size(); i++)
        {   
            for (List l: array)
            {
                Object z = l.get(i);
                List<Object> listes = new ArrayList<Object>();
                listes.add(z);
                System.out.println(listes);
            }               
        }
        br.close();

        System.out.println(array);
    }catch(FileNotFoundException e){
        e.printStackTrace();
    }catch(IOException e){
        e.printStackTrace();
    }      

我做了一个循环来将字符串保存到 ArrayList> 比如:

[[1,10,2,0,154] , [3,10,5,2,10], [2,10,4,1], [3,10,5,1,37]]

我想获取每个列表的元素并比较它们以找到最大的一个(最近的一个),但我不知道这样做..

【问题讨论】:

标签: java string list collections


【解决方案1】:

一般的ListComparator 应该会有所帮助。

static class ListComparator<T extends Comparable<T>> implements Comparator<List<T>> {

    @Override
    public int compare(List<T> o1, List<T> o2) {
        for (int i = 0; i < Math.max(o1.size(), o2.size()); i++) {
            int diff =
                    // Off the end of both - same.
                    i >= o1.size() && i >= o2.size() ? 0
                    // Off the end of 1 - the other is greater.
                    : i >= o1.size() ? -1
                    : i >= o2.size() ? 1
                    // Normal diff.
                    : o1.get(i).compareTo(o2.get(i));
            if (diff != 0) {
                return diff;
            }
        }
        return 0;
    }
}

private static final Comparator<List<Integer>> BY_VERSION = new ListComparator<Integer>().reversed();

public void test(String[] args) {
    String[] tests = {
            "1_10_2_0_154",
            "3_10_5_2_10",
            "2_10_4_1_49",
            "3_10_5_1_37",
            "3_10_5_1_37_0"
    };
    System.out.println("Before: " + Arrays.toString(tests));
    System.out.println("After:  " + Arrays.stream(tests)
            // Split into parts.
            .map(s -> s.split("_"))
            // Map String[] to List<Integer>
            .map(a -> Arrays.stream(a).map(s -> Integer.valueOf(s)).collect(Collectors.toList()))
            // Sort it.
            .sorted(BY_VERSION)
            // Back to a new list.
            .collect(Collectors.toList()));
}

【讨论】:

    【解决方案2】:

    我建议您使用对象方法,使用 compareTo 方法定义一个名为 Version 的类,然后在 Collectionssort /strong> 类,您可以简单地对版本进行排序。

    优势

    • 清理和清除代码
    • 数据验证

    主要:

    public class Main {
    
        public static void main(String[] args){
    
            List<Version> versions = Arrays.asList(
                    Version.create("1_10_2_0_154"),
                    Version.create("3_10_5_2_10"),
                    Version.create("2_10_4_1_49"),
                    Version.create("3_10_5_1_37"));
    
            versions.sort(Version::compareTo);
    
            System.out.println(versions.get(0).toString());
        }
    
    }
    

    版本:

    public class Version implements Comparable<Version> {
    
        private final int major;
        private final int minor;
        private final int bug;
        private final int release;
        private final int build;
    
        public Version(int major, int minor, int bug, int release, int build) {
            this.major = major;
            this.minor = minor;
            this.bug = bug;
            this.release = release;
            this.build = build;
        }
    
        public int getMajor() {
            return major;
        }
    
        public int getMinor() {
            return minor;
        }
    
        public int getBug() {
            return bug;
        }
    
        public int getRelease() {
            return release;
        }
    
        public int getBuild() {
            return build;
        }
    
        @Override
        public String toString() {
            return "Version{" +
                    "major=" + major +
                    ", minor=" + minor +
                    ", bug=" + bug +
                    ", release=" + release +
                    ", build=" + build +
                    '}';
        }
    
    
    
        public static Version create(String value){
    
            String[] splitRes = value.split("_");
            List<Integer> intValues = new ArrayList<>();
    
            for(String v : splitRes){
                intValues.add(Integer.parseInt(v));
            }
    
            return create(intValues);
        }
    
        public static Version create(List<Integer> values){
    
            if(Objects.requireNonNull(values).size() < 5)
                throw new IllegalArgumentException();
    
            return new Version(
                    values.get(0),
                    values.get(1),
                    values.get(2),
                    values.get(3),
                    values.get(4)
            );
        }
    
    
        @Override
        public int compareTo(Version that) {
            if (this.major > that.major) {
                return -1;
            } else if (this.major < that.major) {
                return 1;
            }
    
            if (this.minor > that.minor) {
                return -1;
            } else if (this.minor < that.minor) {
                return 1;
            }
    
            if (this.bug > that.bug) {
                return -1;
            } else if (this.bug < that.bug) {
                return 1;
            }
    
            if (this.release > that.release) {
                return -1;
            } else if (this.release < that.release) {
                return 1;
            }
    
            if (this.build > that.build) {
                return -1;
            } else if (this.build < that.build) {
                return 1;
            }
            return 0;
        }
    }
    

    更新 1

    按照@Henrik 的建议,我使用 Java 8 方法更新了列表排序。

    更新 2

    我颠倒了 compareTo 方法,所以现在您可以简单地进行简单的排序,调用列表上的 sort 方法并传递方法引用 Version::compareTo

    更新 3

    Version 类的更动态的解决方案:

    public class Version implements Comparable<Version> {
    
        private final List<Integer> values;
    
        public Version(List<Integer> values) {
            this.values = values;
        }
    
        public List<Integer> getValues() {
            return values;
        }
    
        @Override
        public String toString() {
    
            return String.join("_", values
                    .stream()
                    .map(Object::toString)
                    .collect(Collectors.toList()));
        }
    
        @Override
        public int compareTo(Version that) {
    
            List<Integer> thatValues = that.getValues();
    
            for(int index = 0; index < values.size(); index++){
    
                Integer value = values.get(index);
                Integer thatValue = thatValues.get(index);
    
                if (value > thatValue) {
                    return -1;
                } else if (value < thatValue) {
                    return 1;
                }
            }
    
            return 0;
        }
    
    
        public static Version create(String value){
    
            String[] splitRes = value.split("_");
            List<Integer> intValues = new ArrayList<>();
    
            for(String v : splitRes){
                intValues.add(Integer.parseInt(v));
            }
    
            return new Version(intValues);
        }
    }
    

    【讨论】:

    • 我同意这种做法。考虑使用添加到 Java 8 中的Comparator 接口的实用方法来实现比较,comparingIntthenComparingInt
    • 我用你的建议更新了我的答案,现在我正在使用 Comparator.reverseOrder() 对列表进行排序
    • 如果我有诸如“3_10_0_4_53_15”而不是“3_10_0_4_53”之类的版本,是否可以使这段代码工作?
    • 这个列表将来会增长吗?您可以添加一个新字段,一切都会起作用,但如果列表是动态的,则需要不同的解决方案(更灵活)
    • 是的,版本的长度可以像“3_10_0_4_53_15”、“3_10_0_4_53”甚至“3_10_0_4”一样改变,你的代码似乎可以完美地使用固定长度的字符串,是否可以让它更多像你说的那样灵活?
    【解决方案3】:

    将你的数组组合成一个数字,然后进行数字比较。

    class Scratch
    {
        public static void main(String[] args)
        {
            List<List<Integer>> arr = new ArrayList<>();
            arr.add(fromArray(new Integer[]{1,10,2,0,154}));
            arr.add(fromArray(new Integer[]{3,10,5,2,10}));
            arr.add(fromArray(new Integer[]{2,10,4,1,49}));
            arr.add(fromArray(new Integer[]{3,10,5,1,37}));
    
            Integer[] maxLengths = {0,0,0,0,0};
            for (List<Integer> v : arr)
            {
                for(int idx = 0; idx < v.size(); idx++)
                {
                    Integer n = v.get(idx);
                    int curMaxLen = maxLengths[idx];
                    maxLengths[idx] = Math.max(n.toString().length(), curMaxLen);
                }
            }
            Long largest = arr.stream().map(v -> {
                StringBuilder result = new StringBuilder();
                for(int idx = 0; idx < v.size(); idx++)
                {
                    Integer n = v.get(idx);
                    int maxLen = maxLengths[idx];
                    result.append(String.format("%-" + maxLen + 's', n).replace(' ', '0'));
                }
                return result.toString();
            }).map(Long::valueOf).max(Comparator.naturalOrder()).get();
            System.out.println(largest);
        }
    
        public static List<Integer> fromArray(Integer[] array)
        {
            List<Integer> list = new ArrayList<>();
            Collections.addAll(list, array);
            return list;
        }
    }
    

    【讨论】:

    • 问题在 Java 中,但您的答案在 Groovy 中。在任何情况下,这都行不通,因为您需要为版本的每个部分使用相同的位数(添加前导零)。
    • 是的,我正在更新。
    【解决方案4】:

    我认为这个文本文件可能非常大,最好动态比较每一行(而不是将所有行存储到集合中进行排序):

    public static String getMostRecentVersion(BufferedReader in) throws IOException {
        final Comparator<String[]> version = (s1, s2) -> {
            int res = 0;
    
            for (int i = 0; i < 5 && res == 0; i++)
                res = Integer.compare(Integer.parseInt(s1[i]), Integer.parseInt(s2[i]));
    
            return res;
        };
    
        String str;
        String resStr = null;
        String[] resPparts = null;
    
        while ((str = in.readLine()) != null) {
            String[] parts = str.split("_");
    
            if (resStr == null || version.compare(parts, resPparts) > 0) {
                resStr = str;
                resPparts = parts;
            }
        }
    
        return resStr;
    }
    

    【讨论】:

      【解决方案5】:

      它没有经过优化,但应该可以工作。您可以同时使用这两个比较器。

      static List<String> versions = Arrays.asList(
              "1_10_2_0_154",
              "3_10_5_2_10",
              "2_10_4_1_49",
              "3_10_5_1_37");
      
      static Comparator<List<Integer>> c = (o1,o2) -> {
          int length = o1.size()>o2.size()?o2.size():o1.size();
          for (int i = 0; i < length; i++) {
              int i1 = o1.get(i);
              int i2 = o2.get(i);
              if (i1 != i2)
                  return i1 - i2;
          }
          return 0;
      };
      static Comparator<List<Integer>> c2 = (o1,o2) -> {
          Iterator<Integer> i1=o1.iterator();
          Iterator<Integer> i2=o2.iterator();
          while (i1.hasNext() && i2.hasNext()){
              int i = i1.next()-i2.next();
              if (i!=0) return i;
          }
          return 0;
      };
      
      static Optional<List<Integer>> getTheMostRecentVersion(List<String> versions) {
          return versions.stream().
                  map(s -> Arrays.stream(s.split("_")).
                          map(Integer::parseInt).
                          collect(Collectors.toList())).max(c2);
      }
      

      【讨论】:

        【解决方案6】:

        你可以写一个Comparator来比较两个列表

        Comparator<List<Integer>> comparator = (list1, list2) -> {
            Iterator<Integer> iteratorA = list1.iterator();
            Iterator<Integer> iteratorB = list2.iterator();
        
            //It iterates through each list looking for an int that is not equal to determine which one precedes the other
            while (iteratorA.hasNext() && iteratorB.hasNext()) {
                int elementA = iteratorA.next();
                int elementB = iteratorB.next();
        
                if (elementA > elementB) {
                    return 1;
                } else if (elementA < elementB) {
                    return -1;
                }
            }
            //All elements seen so far are equal. Use the list size to decide
            return iteratorA.hasNext() ? 1 : iteratorB.hasNext() ? -1 : 0;
        };
        

        你可以把它排序为

        Collections.sort(list, comparator);
        

        编辑:您可以参考David Geirola's answer 将版本字符串转换为 POJO 并将比较器逻辑移到其中。但这与输入字符串格式高度相关/耦合。我的解决方案适用于任何List&lt;List&lt;Integer&gt;&gt;

        【讨论】:

          【解决方案7】:

          一个简单的面向对象的方法是创建一个表示版本号的对象,我们称之为版本号,它有一个工厂方法的构造函数来解析字符串。这个 VersionNumber 类应该实现接口 Comparable 并实现方法 compareTo。

          这里是使用 Comparable Why should a Java class implement comparable? 的提示

          然后您可以轻松地编写一个算法来找到最高版本或谷歌一些可以为您做的库。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-07-30
            • 2015-06-02
            • 1970-01-01
            • 2018-03-02
            • 1970-01-01
            • 1970-01-01
            • 2011-12-16
            相关资源
            最近更新 更多