如果 1+ 个实例具有相同(最小)值,如何从确定最小值的循环中随机选择一个对象?

How to randomly pick one object from a loop that determines smallest value, if 1+ instances have the same (smallest) value?

我写了一个Java程序,由三个相关的类组成;员工、客户和合同。在我的主要方法中,我创建了一个包含所有 3 类 的各种实例的数组;

// Create Clients
Client Client1 = new Client(1, "Client 1", 0);
Client Client2 = new Client(2, "Client 2", 0);

// Create Array of Clients
Client[] clients = new Client[] {Client1, Client2};

// Create Contracts
Contract Contract1 = new Contract("Contract 1", 1, 850, 4, 0, 1, 0);
Contract Contract2 = new Contract("Contract 2", 2, 500, 4, 0, 1, 0);
Contract Contract3 = new Contract("Contract 3", 3, 1500, 3, 0, 1, 0);

// Create Array of Contracts
Contract[] contracts = new Contract[] {Contract1, Contract2, Contract3};

// Create Employees
Employee Employee1 = new Employee(1, "Bradley", 0);
Employee Employee2 = new Employee(2, "Patrick", 0);
Employee Employee3 = new Employee(3, "Erin", 0);
Employee Employee4 = new Employee(4, "Jim", 0);
Employee Employee5 = new Employee(5, "Fredrick", 0);

// Create Array of Employees
Employee[] employees = new Employee[] {Employee1, Employee2, Employee3, Employee4, Employee5};

我在 Contract.Java 中有一个名为 assignContractToEmployeeWithLeastContracts 的函数,它接受 2 个参数、一组员工和合同。函数为:

// Assign contract to employee with least contracts
public void assignContractToEmployeeWithLeastContracts(Employee[] employees, Contract contract) {

    // Assign to employee with minimum contracts
    int minContract = Integer.MAX_VALUE;
    Employee employeeWithMinContracts = null;
    for (Employee employee : employees) {
        if (employee.getCurrentlyAssignedContracts() < minContract) {
            // swap min and employee if true
            employeeWithMinContracts = employee;
            minContract = employeeWithMinContracts.getCurrentlyAssignedContracts();
        }
    }

    employeeWithMinContracts.assignContract(employeeWithMinContracts, contract);
}

我遇到的问题是我需要处理如果 2 名员工都分配了相同(最小)数量的合同会发生什么。如果发生这种情况,我如何随机挑选一名员工?我尝试在 foreach 循环中实现一个种子,但一直在破坏一切。

如有任何帮助,我们将不胜感激,

谢谢, B

如果我理解正确,在您的 assignContractToEmployeeWithLeastContracts 方法中,如果他们有相同数量的合同,您希望将合同随机分配给任何一名员工。
因为目前您会将其分配给合同数量最少的第一位员工。

你的方法将变成这样:

public void assignContractToEmployeeWithLeastContracts(Employee[] employees, Contract contract) {
    int minContract = Integer.MAX_VALUE;
    List<Employee> employeesWithMinContracts = new ArrayList<Employee>();
    for (Employee employee : employees) {
        if (employee.getCurrentlyAssignedContracts() < minContract) {
            employeesWithMinContracts.clear();
            employeesWithMinContracts.add(employee);
            minContract = employee.getCurrentlyAssignedContracts();
        } else if (employee.getCurrentlyAssignedContracts() == minContract) {
            employeesWithMinContracts.add(employee);
        }
    }
    int randomIndex = (int)(Math.random() * employeesWithMinContracts.size());
    employeesWithMinContracts.get(randomIndex).assignContract(contract);
}

我们将利用 Math.random returns [0, 1] 之间的值这一事实,从而随机找到我们的 employeesWithMinContracts 列表索引。

备注:

  • 请注意,我删除了 Employee 作为 assignContract 方法的参数。因为这个方法已经在有问题的 Employee 上调用了。

  • 此外,您的实例名称应以小写字母开头以符合 Java 标准:
    Contract1 变为 contract1
    Employee1 变为 employee1
    等...

如果您希望超过两名员工共享相同数量的最低合同,那么您需要在其中随机选择。您可以通过列出最低合同并随机选择一个来做到这一点。

    // Assign contract to employee with least contracts
public void assignContractToEmployeeWithLeastContracts(Employee[] employees, Contract contract) {

    // Find the employees with the minimum contracts
    int minContract = Integer.MAX_VALUE;
    List <Employee> employeesWithMinContracts = new ArrayList<Employee>();
    for (Employee employee : employees) {
        //add duplicates to the list
        if (employee.getCurrentlyAssignedContracts() == minContract) {
            employeesWithMinContracts.add(employee);
        }
        // swap min and employee if true
        if (employee.getCurrentlyAssignedContracts() < minContract) {
            employeesWithMinContracts.clear();
            employeesWithMinContracts.add(employee);
            minContract = employee.getCurrentlyAssignedContracts();
        }
    }

    //Randomly pick an employee from the group.
    int random = (int)(Math.random() *  employeesWithMinContracts.size() );

    employeeWithMinContracts.assignContract(employeesWithMinContracts.get(random), contract);
}

如果您使用的是 Java 8 或更高版本,则以下内容可能更具可读性:

public void assignContractToEmployeeWithLeastContracts(Employee[] employees, Contract contract) {
    int minContract =  Arrays.stream(employees)
            .mapToInt(Employee::getCurrentlyAssignedContracts)
            .min()
            .getAsInt();
    Employee employeeWithMinContracts = Arrays.stream(employees)
            .filter(e->e.getCurrentlyAssignedContracts() == minContract)
            .findAny()
            .get();

    employeeWithMinContracts.assignContract(employeeWithMinContracts, contract);
}

编辑

虽然上述解决方案中的 findAny() 表现出明确的不确定性,即它可以自由 select 流中的任何元素,让您无法控制元素被选择的可能性;你可能想要一个平均分布的概率。如果是这种情况,请参阅下面的第二个解决方案:

public void assignContractToEmployeeWithLeastContracts(Employee[] employees, Contract contract) {
    int minContract =  Arrays.stream(employees)
            .mapToInt(Employee::getCurrentlyAssignedContracts)
            .min()
            .getAsInt();
    List<Employee> minEmployees =  Arrays.stream(employees)
            .filter(e->e.getCurrentlyAssignedContracts() == minContract)
            .collect(Collectors.toList());

    Random r = new Random();
    Employee employeeWithMinContracts = minEmployees.get(r.nextInt(minEmployees.size()));

    employeeWithMinContracts.assignContract(employeeWithMinContracts, contract);
}