Как случайным образом выбрать один объект из цикла, который определяет наименьшее значение, если экземпляры 1+ имеют одинаковое (наименьшее) значение? - PullRequest
1 голос
/ 12 марта 2019

Я написал программу на Java, состоящую из трех соответствующих классов; Сотрудник, Клиент и Контракт. В моем основном методе я создал массив различных экземпляров всех трех классов;

// 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

Ответы [ 3 ]

3 голосов
/ 12 марта 2019

Если вы ожидаете, что более двух сотрудников будут иметь одинаковое количество минимальных контрактов, вам необходимо выбрать их случайным образом.Вы можете сделать это, составив список минимальных контрактов и выбрав случайный.

    // 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);
}
2 голосов
/ 12 марта 2019

Если я правильно понимаю, в вашем методе 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 возвращает значение в диапазоне [0, 1] и, таким образом, найдет наш список employeeWithMinContracts.индексировать случайным образом.

Примечания:

  • Обратите внимание, что я удалил Employee в качестве аргумента метода assignContract.Так как этот метод уже вызван на Employee в вопросе.

  • Также имена ваших экземпляров должны начинаться со строчной буквы, чтобы соответствовать стандартам Java:
    Contract1 становится contract1
    Employee1 становится employee1
    и т.д ...

1 голос
/ 12 марта 2019

Если вы работаете на 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);
}

EDIT

Хотя findAny() в вышеприведенном решении ведет себя явно недетерминированным, то есть он может свободно выбирать любой элемент в потоке, что не позволяет вам контролировать вероятность выбора элемента; Вы можете хотеть иметь одинаково распределенную вероятность. Если это так, см. Второе решение ниже:

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