英文:
How to print random unique values of multiple elements from a hashmap
问题
以下是您提供的代码部分的翻译:
我正在处理一个程序,其中我有一个任务列表,每个任务都有预计的持续时间。例如:`{任务:洗衣,时间:1000},{任务:做饭,时间:2000},{任务:清洁,时间:3000}`等。我希望选择多个项目并递增一个整数变量,同时将任务打印到控制台。我的方法是首先创建一个HashMap,其中任务是键,时间是值。然后,我将时间值放入一个ArrayList中,并迭代所需的次数,递增时间变量。
我遇到的问题是我需要唯一的数字,所以我选择使用HashSet只跟踪唯一的值。然而,我无法使用这种方法打印任务,如果我迭代一定次数,如果键被重复,可能无法在集合中获得足够的值。
以下是这部分代码:
int time = 0;
Random rand = new Random();
ArrayList<Integer> eta = new ArrayList<Integer>(tasks.values());
HashSet<Integer> set = new HashSet<>();
for (int i = 0; i <= 5; i++) {
int randomIndex = rand.nextInt(eta.size());
int tim = eta.get(randomIndex);
set.add(tim);
}
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
time += it.next();
}
return time;}
我将时间值打印到控制台,并在获得3个值后出现了`NoSuchElementException`错误而崩溃。是否有方法可以解决这个问题,或者是否有更好的方法来解决这个问题。最好能够随机选择5个值,并打印任务并递增时间变量。
谢谢。
英文:
I am working on a program where I have a list of tasks each with a predicted time duration. For example: {task: laundry, time: 1000}, {task: cooking, time: 2000}, {task: cleaning, time: 3000}
, etc. I want to pick multiple items and increment an integer variable while printing out the task to the console. My approach is to first make a HashMap with the task being the key and time being value. I then put the time values in an ArrayList and iterate through the number of times I need and increment the time variable.
The issue I run into is I need unique numbers, so I opted to use a hashset to only keep track of unique values. However, I cannot print the task with this approach and if I iterate a certain number of times, I might not get enough values in the set if the key is duplicated.
Here is my code for this part.
int time = 0;
Random rand = new Random();
ArrayList<Integer> eta = new ArrayList<Integer>(tasks.values());
HashSet <Integer> set = new HashSet<>();
for (int i = 0; i<=5; i++) {
int randomIndex = rand.nextInt(eta.size());
int tim = eta.get(randomIndex);
set.add(tim);
}
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
time += it.next();
}
return time;}
I printed the time values to the console and got 3 values before it crashed with a NoSuchElementException
error. Is there a way I can fix this, or is there a better approach to do this problem. It would be best if I can pick the 5 values at random and print the task and increment the time variable.
Thank You.
答案1
得分: 0
### 两个列表 ###
从你的方法开始,你还可以将键(任务名称)添加到一个“列表”中,这样你就可以通过随机索引来检索它们。
一旦你获得一个索引,就从这两个列表中删除相应的元素,这样下次你将找到另一个有效的元素,而不是重复的元素。
int time = 0;
Random rand = new Random();
List<Integer> eta = new ArrayList<>();
List<String> taskNames = new ArrayList<>();
tasks.forEach((k,v) -> {
eta.add(v);
taskNames.add(k);
});
for (int i = 0; i < 5; i++) {
int randomIndex = rand.nextInt(eta.size());
Integer taskTime = eta.remove(randomIndex);
String taskName = taskNames.remove(randomIndex);
System.out.println(taskName + ": " + taskTime);
time += taskTime;
}
System.out.println("总时间:" + time);
### 单个列表 ###
实际上,你不需要值列表(eta),因为你可以通过键有效地从HashMap中检索值。
所以你实际上只需要键的列表:
int time = 0;
Random rand = new Random();
List<String> taskNames = new ArrayList<>(tasks.keySet());
for (int i = 0; i < 5; i++) {
int randomIndex = rand.nextInt(taskNames.size());
String taskName = taskNames.remove(randomIndex);
Integer taskTime = tasks.get(taskName);
System.out.println(taskName + ": " + taskTime);
time += taskTime;
}
System.out.println("总时间:" + time);
### 洗牌 ###
你可以使用“Collections.shuffle”来洗牌列表,并考虑前5个元素:
int time = 0;
List<String> taskNames = new ArrayList<>(tasks.keySet());
Collections.shuffle(taskNames);
for (int i = 0; i < 5; i++) {
String taskName = taskNames.get(i);
Integer taskTime = tasks.get(taskName);
System.out.println(taskName + ": " + taskTime);
time += taskTime;
}
System.out.println("总时间:" + time);
### 洗牌 + 流 ###
你可以使用流API来获取总时间。
要打印任务名称,你必须使用“peek”,这通常仅用于调试,但在你的情况下似乎是合适的:
List<String> taskNames = new ArrayList<>(tasks.keySet());
Collections.shuffle(taskNames);
int time = taskNames.stream()
.limit(5)
.peek(System.out::println)
.mapToInt(tasks::get)
.sum();
System.out.println("总时间:" + time);
### 带有随机的流 ###
与其使用“Collections.shuffle”,我们可以使用流API生成随机索引:
List<String> taskNames = new ArrayList<>(tasks.keySet());
int time = new Random().ints(0, taskNames.size())
.distinct()
.limit(5)
.mapToObj(taskNames::get)
.peek(System.out::println)
.mapToInt(tasks::get)
.sum();
System.out.println("总时间:" + time);
英文:
Two Lists
Starting from your approach, you could add also the keys (task names) in a List
so you can retrieve them by the random index.
Once you get an index, remove from the two lists the respective element so the next time you are gonna find another valid element and not a repeated one.
int time = 0;
Random rand = new Random();
List<Integer> eta = new ArrayList<>();
List<String> taskNames = new ArrayList<>();
tasks.forEach((k,v) -> {
eta.add(v);
taskNames.add(k);
});
for (int i = 0; i < 5; i++) {
int randomIndex = rand.nextInt(eta.size());
Integer taskTime = eta.remove(randomIndex);
String taskName = taskNames.remove(randomIndex);
System.out.println(taskName + ": " + taskTime);
time += taskTime;
}
System.out.println("Total time: " + time);
One List
You actually don't need the value list (eta
) since you can retrieve the values from the HashMap
efficiently with the keys.
So you actually need only the keys list:
int time = 0;
Random rand = new Random();
List<String> taskNames = new ArrayList<>(tasks.keySet());
for (int i = 0; i < 5; i++) {
int randomIndex = rand.nextInt(taskNames.size());
String taskName = taskNames.remove(randomIndex);
Integer taskTime = tasks.get(taskName);
System.out.println(taskName + ": " + taskTime);
time += taskTime;
}
System.out.println("Total time: " + time);
Shuffle
Instead of finding a random index you could shuffle the list with Collections.shuffle
and consider the first 5 elements:
int time = 0;
List<String> taskNames = new ArrayList<>(tasks.keySet());
Collections.shuffle(taskNames);
for (int i = 0; i < 5; i++) {
String taskName = taskNames.get(i);
Integer taskTime = tasks.get(taskName);
System.out.println(taskName + ": " + taskTime);
time += taskTime;
}
System.out.println("Total time: " + time);
Shuffle + Stream
You could use the streaming API to get the total time.
To print the task name you have to use peek
, which should be used only for debugging purposes but seems appropriate in your case:
List<String> taskNames = new ArrayList<>(tasks.keySet());
Collections.shuffle(taskNames);
int time = taskNames.stream()
.limit(5)
.peek(System.out::println)
.mapToInt(tasks::get)
.sum();
System.out.println("Total time: " + time);
Stream with Random
Instead of Collections.shuffle
we could generate the random indexes using the streaming API:
List<String> taskNames = new ArrayList<>(tasks.keySet());
int time = new Random().ints(0, taskNames.size())
.distinct()
.limit(5)
.mapToObj(taskNames::get)
.peek(System.out::println)
.mapToInt(tasks::get)
.sum();
System.out.println("Total time: " + time);
答案2
得分: 0
"NoSuchElementException"出现的原因是因为您在迭代器的末尾继续运行。
while (it.hasNext()) {
System.out.println(it.next());
time += it.next();
}
每次调用'next'都会推进迭代器,因此您会消耗两个元素。对于奇数个元素,最后一次循环时hasNext()为true,您会读取最后一个元素(在println调用中的next()调用中),然后再次调用next(),导致失败。
在hasNext()之后只调用一次next()。
while (it.hasNext()) {
Integer n = it.next();
System.out.println(n);
time += n;
}
英文:
The reason for the NoSuchElementException is that you run off the end of the iterator.
while(it.hasNext()){
System.out.println(it.next());
time += it.next();
}
Each time you call 'next' you advance the iterator, so you are consuming two elements. Given an odd number of elements, last time around the loop hasNext() is true, you read the last element (with the call to next() in the println call) and then you'll call next() again, and fail.
Call next() once after hasNext().
while(it.hasNext()){
Integer n = it.next();
System.out.println(n);
time += n;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论