如何从哈希映射中打印多个元素的随机唯一值

huangapple go评论125阅读模式
英文:

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&lt;Integer&gt; eta = new ArrayList&lt;Integer&gt;(tasks.values());
	HashSet &lt;Integer&gt; set = new HashSet&lt;&gt;();
	
	for (int i = 0; i&lt;=5; i++) {
		int randomIndex = rand.nextInt(eta.size());
		int tim = eta.get(randomIndex);
		set.add(tim);
	}
	Iterator&lt;Integer&gt; 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&lt;Integer&gt; eta = new ArrayList&lt;&gt;();
List&lt;String&gt; taskNames = new ArrayList&lt;&gt;();
tasks.forEach((k,v) -&gt; {
eta.add(v);
taskNames.add(k);
});
for (int i = 0; i &lt; 5; i++) {
int randomIndex = rand.nextInt(eta.size());
Integer taskTime = eta.remove(randomIndex);
String taskName = taskNames.remove(randomIndex); 
System.out.println(taskName  + &quot;: &quot; + taskTime);
time += taskTime;
}
System.out.println(&quot;Total time: &quot; + 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&lt;String&gt; taskNames = new ArrayList&lt;&gt;(tasks.keySet());
for (int i = 0; i &lt; 5; i++) {
int randomIndex = rand.nextInt(taskNames.size());
String taskName = taskNames.remove(randomIndex);
Integer taskTime = tasks.get(taskName);
System.out.println(taskName  + &quot;: &quot; + taskTime);
time += taskTime;
}
System.out.println(&quot;Total time: &quot; + 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&lt;String&gt; taskNames = new ArrayList&lt;&gt;(tasks.keySet());
Collections.shuffle(taskNames);
for (int i = 0; i &lt; 5; i++) {
String taskName = taskNames.get(i);
Integer taskTime = tasks.get(taskName);
System.out.println(taskName  + &quot;: &quot; + taskTime);
time += taskTime;
}
System.out.println(&quot;Total time: &quot; + 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&lt;String&gt; taskNames = new ArrayList&lt;&gt;(tasks.keySet());
Collections.shuffle(taskNames);
int time = taskNames.stream()
.limit(5)
.peek(System.out::println)
.mapToInt(tasks::get)
.sum();
System.out.println(&quot;Total time: &quot; + time);

Stream with Random

Instead of Collections.shuffle we could generate the random indexes using the streaming API:

List&lt;String&gt; taskNames = new ArrayList&lt;&gt;(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(&quot;Total time: &quot; + 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;
}

huangapple
  • 本文由 发表于 2020年8月16日 07:34:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/63431726.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定