首页 > 解决方案 > 在 Java 中以机会百分比随机获取价值

问题描述

我希望能够根据每个项目的某个预定义的机会百分比返回(在我们的例子中,例如,显示)枚举项目。此枚举的代码说明如下:

package me.lucas.test;

public enum Item {

    ITEM_1("Item 1", 30),
    ITEM_2("Item 2", 30),
    ITEM_3("Item 3", 10),
    ITEM_4("Item 4", 65);

    private final String name;
    private final int percentage;

    Item(String name, int percentage) {
        this.name = name;
        this.percentage = percentage;
    }

    public String getName() {
        return name;
    }

    public int getPercentage() {
        return percentage;
    }

}

此外,这些项目将存储在列表中。

package me.lucas.test;

import java.util.ArrayList;
import java.util.List;

public class Program {

    private final List<Item> items = new ArrayList<>();

    /**
     * Displays an item among those in the list, according to their percentage chance of appearing.
     * @param items The items
     */
    public void displayItem(List<Item> items) {
        Item item;

        item = ?

        System.out.println("Selected item : " + item.getName() + " with percentage : " + item.getPercentage());
    }

}

即,如本例所示,两个项目可以具有相同百分比的出现机会。

我还查看了以下主题(Java Random Percentage Chance),但就我而言,百分比不是直接在表达式中预定义的,而是在枚举中预定义的。

所以我很感激你的帮助。预先感谢您抽出宝贵时间帮助我。

标签: javarandompercentageenumeration

解决方案


从视觉上讲,您实现了机会之轮

轮子将落在 1 到 100 的任何位置。现在你只需要读出这个位置有哪些可能性。如果总和小于 100,则此位置可能没有任何内容。如果总和 > 100,则该位置可能有多个项目。

查克尼之轮

所有百分比都是从 1 到 100 - 通过模数实现的。您生成的随机数介于 1 和 100 之间,或者在本例中介于 0 和 99 之间(请参阅 Random 的 Javadoc)。

在代码中,这可能如下所示:

public class RandomExample<T extends Object> {
    List<Item> items = new LinkedList<>();
    Random rand = new Random();
    
    public void addItem(int percentage, T object) {
        items.add(new Item(percentage, object));
    }
    
    public List<Item> getRandom() {
        List<Item> result = new ArrayList<>();
        int hit = rand.nextInt(100);
        items.forEach(i -> {
            if(i.isHit(hit)) {
                result.add(i);
            }
        });
        return result;
    }
    
    public class Item {
        private int percentage;
        private T object;
        private int hitLow;
        private int hitHigh;
        
        public Item(int percentage, T object) {
            this.percentage = percentage;
            this.object = object;
            int sum = 0;
            for(Item i : items) {
                sum+=i.getPercentage();
            }
            hitLow = sum % 100;
            hitHigh = (sum+percentage) % 100;
        }
        
        public int getPercentage() {
            return percentage;
        }
        
        public T getObject() {
            return object;
        }
        
        public boolean isHit(int hitVal) {
            boolean isHit = hitLow == hitHigh; //exactly 100%
            isHit |= hitLow <= hitVal && hitHigh >= hitVal;
            return isHit;
        }
    }

}

该方法RandomExample.Item.isHit(int)仍然需要一个额外的条件来正确处理机会,它环绕在 100 左右(例如hitLow = 90hitHigh = 10)。但是您了解了这个概念,并且应该能够根据您的需要对其进行调整。

你需要问自己的另一个问题是:如果有人通过了大于 100 的百分比会发生什么。我的直觉告诉你应该抛出一个异常。但这是由您决定和实施的。


推荐阅读