在这种特殊情况下,我个人认为如果您使用HashMap 或Map Interface 来存储所需的数据可能会更好一些。它非常适合这类事情,因为 User Name 应该是唯一的,并且可以用作 Key,而 Rank 作为 Value,因为多个用户可能包含相同的排名值:
Map<String, Integer> map = new HashMap<>();
另一件可能让生活更轻松的事情是用户在一行中输入排名以及与该排名相关的用户名,并用空格或制表符或其他任何内容分隔,例如:
Ranking #1:
Enter a Rank value followed by a User Name separated with space,
for example: 250 John Doe. Enter 'd' when done.
Your entry: --> |
当然需要进行验证以确保正确输入,但使用String#matches() 方法和一个小的Regular Expression(正则表达式)并不太难,例如:
if (!myString.matches("^\\d+\\s+.{1,}$")) {
System.err.println("Invalid Entry! Try again...");
System.err.println();
myString = "";
continue;
}
上面传递给 String#matches() 方法的正则表达式 "^\\d+\\s+.{1,}$" 的作用是验证提供的 User 条目的第一个组件实际上是一个字符串表示一个由一位或多位数字组成的整数值。然后它检查以确保在该数值后面至少有一个空格,然后在它期望在空格之后看到至少 1 (或更多)任何字符的空格之后,这基本上是是用户名。当然,如果用户输入数据不正确,则会发出 Invalid Entry 警告,并为用户提供再次尝试输入的机会。
一旦获得有效输入,现在当然需要将数据拆分成各自的数据类型,然后才能应用到 Map Interface 对象。这当然是通过String#split() 方法完成的:
String[] stringParts = myString.split("\\s+");
这将创建一个名为 stringParts 的 String[] 数组。 \\s+ 正则表达式告诉 split() 方法将字符串拆分为一个或多个空格' '(或制表符\t,换行符\n,回车符\r,形式-feeds \f 和垂直列表 \x0B)。这将涵盖用户所需条目的几乎所有情况。
现在我们有了数组,我们知道该数组的第一个元素将是提供的排名值。在添加到我们的 Map 之前,我们希望将其转换为 Integer 数据类型,如下所示:
int rank = Integer.parseInt(stringParts[0]);
现在我们需要用户名。因为在此示例中,我们还允许使用多个名称,例如名字和姓氏,所以需要将这些名称加在一起,以便从中创建一个单一的用户名字符串。请记住,我们在空格上拆分数据条目,因此如果有多个名称,我们可能在 stringParts[] 数组中拥有两个以上的元素。我们需要构建用户名字符串。我们使用 for 循环和 StringBuilder 类来执行此操作,例如:
String[] stringParts = tmp.split("\\s+");
int rank = Integer.parseInt(stringParts [0]);
StringBuilder sb = new StringBuilder("");
for (int i = 1; i < stringParts .length; i++) {
if (!sb.toString().isEmpty()) {
sb.append(" ");
}
sb.append(stringParts [i]);
}
String userName = sb.toString();
好的...现在我们有了用户名,所以让我们确保使用该用户名的排名尚未包含在地图中:
if (map.containsKey(userName)) {
System.err.println("A ranking for '" + userName
+ "' has already been supplied! Try again...");
System.err.println();
myString = "";
continue;
}
如果我们通过了这一点,那么一切都很好,我们可以将数据添加到 Map:
map.put(userName, rank);
这可能看起来有点啰嗦,但在我看来,事实并非如此。以下是一个工作示例或以上所有正在使用的示例:
Scanner userInput = new Scanner(System.in);
Map<String, Integer> map = new HashMap<>();
int count = 0;
String tmp = "";
while (tmp.isEmpty()) {
System.out.println("Ranking #" + (count+1) + ":");
System.out.print("Enter a Rank value followed by a User Name separated "
+ "with space,\nfor example: 250 John Doe. Enter 'd' when done.\n"
+ "Your entry: --> ");
tmp = userInput.nextLine();
if (tmp.equalsIgnoreCase("d")) {
break;
}
if (!tmp.matches("^\\d+\\s+.{1,}$")) {
System.err.println("Invalid Entry! Try again...");
System.err.println();
tmp = "";
continue;
}
String[] parts = tmp.split("\\s+");
int rank = Integer.parseInt(parts[0]);
StringBuilder sb = new StringBuilder("");
for (int i = 1; i < parts.length; i++) {
if (!sb.toString().isEmpty()) {
sb.append(" ");
}
sb.append(parts[i]);
}
String userName = sb.toString();
if (map.containsKey(userName)) {
System.err.println("A ranking for '" + userName
+ "' has already been supplied! Try again...");
System.err.println();
tmp = "";
continue;
}
count++;
map.put(userName, rank);
tmp = "";
System.out.println();
}
// Sort the map by RANK value in 'descending' order:
Map<String, Integer> sortedMap = map.entrySet().stream().sorted(Map.Entry.<String,
Integer>comparingByValue().reversed()).collect(java.util.stream.Collectors.toMap(Map.Entry::
getKey, Map.Entry::getValue,(e1, e2) -> e1, java.util.LinkedHashMap::new));
// If you want the Rank values sorted in 'Ascending' order then use below instead:
/* Map<String, Integer> sortedMap2= map.entrySet().stream().sorted(Map.Entry.<String,
Integer>comparingByValue()).collect(java.util.stream.Collectors.toMap(Map.Entry::
getKey, Map.Entry::getValue,(e1, e2) -> e1, java.util.LinkedHashMap::new)); */
// Display the rankings in Console Window:
System.out.println();
System.out.println("You entered " + count + " rankings and they are as follows:");
System.out.println();
// Table header
String header = String.format("%-4s %-15s %-6s",
"No.", "User Name", "Rank");
System.out.println(header);
// The header underline
System.out.println(String.join("", java.util.Collections.nCopies(header.length(), "=")));
// The rankings in spaced format...
count = 1;
for (Map.Entry<String,Integer> enties : sortedMap.entrySet()) {
System.out.printf("%-4s %-15s %-6d %n",
String.valueOf(count) + ")",
enties.getKey(),
enties.getValue());
count++;
}
当上述代码运行时,用户被要求提供一个排名值和一个与该排名相关的用户名。然后要求用户输入另一个和另一个,直到该用户输入“d”(代表完成)。然后,所有提供的条目都以表格类型格式显示在控制台窗口中。地图中的排名在显示之前已经按降序排列(最高排名在前)。如果您更喜欢升序,那么还会提供该代码,但目前已被注释掉。