简体   繁体   English

如何从 hashmap 打印多个元素的随机唯一值

[英]How to print random unique values of multiple elements from a hashmap

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.例如: {task: laundry, time: 1000}, {task: cooking, time: 2000}, {task: cleaning, time: 3000}等任务到控制台。 My approach is to first make a HashMap with the task being the key and time being value.我的方法是首先制作一个 HashMap,任务是关键,时间是价值。 I then put the time values in an ArrayList and iterate through the number of times I need and increment the time variable.然后,我将时间值放入 ArrayList 并遍历我需要的次数并增加时间变量。

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.我将时间值打印到控制台并在它因NoSuchElementException错误而崩溃之前获得了 3 个值。 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.如果我可以随机选择 5 个值并打印任务并增加时间变量,那将是最好的。

Thank You.谢谢你。

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.从您的方法开始,您还可以在List中添加键(任务名称),以便您可以通过随机索引检索它们。

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.您实际上不需要值列表 ( eta ),因为您可以使用键有效地从HashMap检索值。

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:您可以使用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("Total time: " + time);

Shuffle + Stream随机播放 + Stream

You could use the streaming API to get the total time.您可以使用流式 API 来获取总时间。

To print the task name you have to use peek , which should be used only for debugging purposes but seems appropriate in your case:要打印任务名称,您必须使用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("Total time: " + time);

Stream with Random Stream 随机

Instead of Collections.shuffle we could generate the random indexes using the streaming API:我们可以使用流式Collections.shuffle生成随机索引,而不是 Collections.shuffle:

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);

The reason for the NoSuchElementException is that you run off the end of the iterator. NoSuchElementException 的原因是您在迭代器的末尾运行。

 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.每次调用“next”时,都会推进迭代器,因此您正在消耗两个元素。 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.给定奇数个元素,最后一次循环 hasNext() 为真,您读取最后一个元素(在 println 调用中调用 next()),然后再次调用 next() 并失败。

Call next() once after hasNext().在 hasNext() 之后调用 next() 一次。

 while(it.hasNext()){
    Integer n = it.next();
    System.out.println(n);
    time += n;
 }

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

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