繁体   English   中英

按字典顺序排序数组列表,忽略整数

[英]Sort Array List lexicographically ignoring integers

我有这个代码。 我想订购一个字符串列表。 列表中的每个项目都由一个三个单词的句子组成。 我想忽略第一个单词并用第二个和第三个单词按字典顺序对句子进行排序。 如果第二个或第三个单词包含 integer,我想忽略对它们进行排序,但将它们添加到列表的末尾。 例如: (19th apple orange, 17th admin 7th, 19th apple table) 应在列表中排序为 (19th apple orange, 19th apple table, 17th admin 7th) 到目前为止,我的代码仅忽略第一个单词并按字典顺序排序 rest名单中的

public static List<String> sortOrders(List<String> orderList) {
     // Write your code here
    Collections.sort( orderList,
    (a, b) -> a.split(" *", 2)[1].compareTo( b.split(" *", 2)[1] )
    );
    
    return orderList;
}

在您的比较方法中,首先检查数字,然后检查字符串。 您只需将代码添加到您描述的步骤中:

这是您描述的伪代码

...
(a,b) -> {
    // Every item in the list consists of a three word sentence.
    var awords = a.split(" ")
    var bwords = a.split(" ")
   
    // I want to ignore the first word
    var as = awords[1] + " " awords[2]
    var bs ...  
    //  and sort the sentence lexicographically with the 2nd and 3rd words.
    var r = as.compareTo(bs) 
    
    // If the 2nd or 3rd words contain an integer, I want to ignore sorting them but add them to the end of the list
    if ( as.matches(".*\\d.*) ) {
        return -1
     } else { 
        return r
     }

}
...

如果两者都有数字,例如a 1 aa 1 b ,尚不清楚该怎么办,但这是您必须澄清的事情。

所以基本上你只需要 go,划分问题中的每个语句并添加一些解决它的代码(如下例所示)

您可能会注意到存在一些差距(例如如果其中两个有字符串该怎么办)。 一旦你有了一个可行的解决方案,你就可以清理它。

另一种具有类似想法的替代方案

var as = a.substring(a.indexOf(" ")) // "a b c" -> "b c"
var bs = b.substring(b.indexOf(" ")) // "a b c" -> "b c"
return as.matches("\\d+") ? -1 : as.compareTo(bs);

记住compare(T,T)方法返回 < 0 如果 a “低于” b,所以如果a有数字,它总是“高”,因此应该返回1 ,如果b有数字,那么a将“低” ,因此它应该返回-1 ,否则只比较字符串

这是完整的程序:

import java.util.*;

public class Sl {

  public static void main(String ... args ) {

    var list = Arrays.asList("19th apple orange", "17th admin 7th", "19th apple table");

    Collections.sort(list, (a, b) -> {
      // just use the last two words
      var as = a.substring(a.indexOf(" "));
      var bs = b.substring(b.indexOf(" "));

      // if a has a number, will always be higher
      return as.matches(".*\\d+.*") ? 1 
         // if b has a number, a will always be lower
         : bs.matches(".*\\d+.*") ? -1 
         // if none of the above, compare lexicographically the strings
         : as.compareTo(bs);
    });

    System.out.println(list);
  }
}

一不小心,就会得到Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!

为了防止发生这种情况,您可以通过创建一个解析字符串并检查第二个和第三个元素的整数的比较器来执行以下操作。 如果第一个元素没有整数但第二个元素有,它将被发送到底部,因为通过返回 1 认为第二个元素更大。但是下一个条件必须只检查第二个元素并返回 -1 表示它比增益小,它排在列表的底部。

public static List<String> sortOrders(List<String> orderList) {
    Comparator<String> comp = (a, b) -> {
        String[] aa = a.split("\\s+", 2);
        String[] bb = b.split("\\s+", 2);
        boolean aam = aa[1].matches(".*[0-9]+.*");
        boolean bbm = bb[1].matches(".*[0-9]+.*");
        
        return aam && !bbm ? 1 : bbm ? -1 :
           aa[1].compareTo(bb[1]);
    };
    
    return orderList.stream().sorted(comp).toList();    
}

如果要保留原始数据,请使用上述方法。 如果要就地排序,请应用上面定义的比较器并使用Collections.sort(data, comp)

我已经使用以下数据生成代码对此进行了广泛测试,该代码生成了满足您要求的随机字符串。 我建议你测试你得到的任何答案(包括这个),以确保它满足你的要求。

String letters = "abcdefghijklmnopqrstuvwxyz";
Random r = new Random(123);
List<String> data = r.ints(200000, 1, 100).mapToObj(i -> {
    StringBuilder sb = new StringBuilder();
    boolean first = r.nextBoolean();
    boolean second = r.nextBoolean();
    int ltr = r.nextInt(letters.length());
    String fstr = letters.substring(ltr,ltr+1);
    ltr = r.nextInt(letters.length());
    String sstr = letters.substring(ltr,ltr+1);
    sb.append(fstr).append(first ? ltr : "").append(" ");
    sb.append(fstr);
    if (first) {
        sb.append(r.nextInt(100));
    }
    sb.append(" ").append(sstr);
    
    if (!first && second) {
        sb.append(r.nextInt(100));
    }
     
    return sb.toString();
}).collect(Collectors.toCollection(ArrayList::new));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM