Поиск элемента в массиве с максимальным значением
На экране 4 CheckBox`а (сила, выносливость, разум, скорость). В RecyclerView показываем список объектов у которых есть все эти параметры. Если чекнуть CheckBox то из этого списка нужно найти элемент с максимальным значением выбранного параметра и показать этот элемент.
Если чекнуть сразу все CheckBox то выбор максимального по всем параметрам будет..
Есть ViewModel в который отправляются event`ы с состоянием чекбоксов при смене их состояния, в этом ViewModel есть кэш отображаемого списка.
Посоветуйте, пожалуйста, как лучше сделать поиск элемента с максимальными значениями.
Мне на ум ничего кроме этого не приходит. Функция вызывается каждый раз при смене состояния какого либо чекбокса и находит максимальное по полям для которых чекбокс включен (true)
fun search(elements : List<Data>, powerIsChecked: Boolean, enduranceIsChecked: Boolean, speedIsChecked: Boolean) {
val maxElement = if (powerIsChecked && enduranceIsChecked && mindIsChecked && speedIsChecked) elements.maxBy {
//если чекнуты все чекбоксы ищем по сумме всех свойств
it.power + it.endurance + it.mind + it.speed
} else if (powerIsChecked && enduranceIsChecked ) elements.maxBy {
//иначе по сумме двух других и т.д. портянка из if else
it.power + it.endurance
} else if (powerIsChecked) elements.maxBy {
it.power
} else ...
}
Но мне либо в функции search нужно портянку из if else делать, либо в рантайме какой то условно придикат каждый раз инициализировать(разные классы с разной логикой поиска).. Вот никак не пойму как сделать адекватнее
Ответы (1 шт):
Я не совсем понимаю как можно найти элемент с максимальными 4-мя параметрами? Тут надо определиться.
вам нужно к примеру максимальное значение суммы всех параметров?
вам нужно брать некий приорите. Например сперва ищем объекты с макс выносливостью, если таких более 1ого, то дальше фильтруем по макс силе и т.д.
Но в любом случае я написал бы свой интерфейс что-то вроде такого:
interface Predicate<T> {
apply(input : T?) : Boolean
}
И написал бы функцию:
fun search(predicate : Predicate) : YouObject {
return elements.maxBy { predicate.apply() }
}
Таким образом вы можете на каждый ваш кейс создать класс реализующий интерфейс Predicate и просто передавать его в функцию. Вы инкапсулируете логику поиска предиката и вам не придется писать безмерно большие if else и добавлять туда новый if else всякий раз когда будет добавляться новый кейс.
Тут можно пойти дальше и к примеру в функцию search передавать список предикатов и проверять по всему списку. Тогда вам по сути придется создать всего 4 класса с предикатами, а в месте вызова функции просто добавлять нужную комбинацию. Это будет даже лучше. Но ща вот сходу не напишу такую функцию, но если сами не сообразите, то отпишитесь, я дам вам пример.
UPD Вот пример из реального проекта.
Один из предикатов:
public class AccountTypeFilter implements Predicate<Account> {
private final AccountType[] types;
public AccountTypeFilter(AccountType... types) {
this.types = types;
}
@Override
public boolean apply(Account input) {
for (AccountType type : types) {
if (input.getAccountType().equals(type)) {
return true;
}
}
return false;
}
}
Вот пример как эти предикаты добавляются в список:
GetAccountsParams(Builder builder) {
predicates.addAll(builder.predicates);
if (builder.accountType != null) {
predicates.add(new AccountTypeFilter(builder.accountType));
}
if (builder.hasCard != null) {
predicates.add(new AccountWithCardFilter(builder.hasCard));
}
if (!builder.withHidden) {
predicates.add(new HiddenAccountFilter());
}
}
И потом собственно проверка:
private class AndPredicate<T> constructor(
private List<Predicate<T>> components;
) implements Predicate<T>, Serializable {
public boolean apply(@Nullable T t) {
for (Int i = 0; i < components.size(); i++) {
if (!components.get(i).apply(t)) {
return false
}
}
return true
}
}
По этой же аналогии вы можете написать свой интерфейс, который будет добавлять какое-то условие в вашу функцию search() по которым вы и будете искать ваш элемент.