Skip to content

Instantly share code, notes, and snippets.

@AlexRogalskiy
Last active October 25, 2022 23:43
Show Gist options
  • Save AlexRogalskiy/aafdcf52f0f4e6fcb404ddaddb45d525 to your computer and use it in GitHub Desktop.
Save AlexRogalskiy/aafdcf52f0f4e6fcb404ddaddb45d525 to your computer and use it in GitHub Desktop.
Greedy collection of toys
import java.lang.*;
import java.util.*;
import java.util.stream.*;
import java.util.function.*;
import java.util.concurrent.*;
import static java.util.stream.Collectors.*;
abstract class Toy {
public abstract double volume();
}
class Cube extends Toy {
private final double edge;
public Cube(double edge) {
this.edge = edge;
}
public double volume() {
return Math.pow(edge, 3);
}
}
class Ball extends Toy {
private final double radius;
public Ball(double radius) {
this.radius = radius;
}
public double volume() {
return Math.pow(radius, 3) * Math.PI * 4 / 3;
}
}
public class Main
{
public static List<Toy> getMaxCountToys(final List<Cube> cubes, final List<Ball> balls, double maxCapacity) {
final List<Toy> cubesByCapacity = sortAndFilterBy(
cubes,
Comparator.comparingDouble(Toy::volume),
createFilterByCapacity(maxCapacity)
);
System.out.println("\n>>> Input collection of cubes filtered by max capacity: \n" + mapToString(cubesByCapacity));
final List<Toy> ballsByCapacity = sortAndFilterBy(
balls,
Comparator.comparingDouble(Toy::volume),
createFilterByCapacity(maxCapacity)
);
System.out.println("\n>>> Input collection of balls filtered by max capacity: \n" + mapToString(ballsByCapacity));
// Version #1
final List<Toy> result = Stream.of(cubesByCapacity, ballsByCapacity)
.flatMap(Collection::stream)
.sorted(Comparator.comparingDouble(Toy::volume))
.filter(createFilterByCapacity(maxCapacity))
.collect(toList());
// Version #2
//final List<Toy> result = inclusiveZipBy(cubesByCapacity, ballsByCapacity, createFilterByCapacity(maxCapacity));
return result;
}
public static void main(final String[] args) {
// Generate input list of Cube items
final List<Cube> cubes = generateList(1, 10, ThreadLocalRandom.current().nextInt(10), Cube::new);
System.out.println("\n>>> Input collection of cubes: \n" + mapToString(cubes));
// Generate input list of Ball items
final List<Ball> balls = generateList(1, 10, ThreadLocalRandom.current().nextInt(10), Ball::new);
System.out.println("\n>>> Input collection of balls: \n" + mapToString(balls));
// Generate output list of Toy items
final List<Toy> result = getMaxCountToys(cubes, balls, 100);
System.out.println("\n>>> Output collection of toys: \n" + mapToString(result));
}
private static <T extends Toy, E extends List<? extends T>> List<T> sortAndFilterBy(final E items, final Comparator<? super T> comparator, final Predicate<T> predicate) {
return filterBy(sortBy(items, comparator), predicate);
}
private static <T extends Toy, E extends List<? extends T>> List<T> sortBy(final E items, final Comparator<? super T> comparator) {
return items
.stream()
.sorted(comparator)
.collect(toList());
}
private static <T extends Toy, E extends List<? extends T>> List<T> filterBy(final E items, final Predicate<T> predicate) {
return items
.stream()
.reduce(
new ArrayList<>(),
(list, item) -> {
if(predicate.test(item)) {
list.add(item);
}
return list;
},
(list1, list2) -> {
list1.addAll(list2);
return list1;
}
);
}
private static <T extends Toy, E extends List<T>> List<T> inclusiveZipBy(final E items1, final E items2, final Predicate<T> predicate) {
final List<T> result = new ArrayList<>();
int i1 = 0, i2 = 0;
while(i1 < items1.size() && i2 < items2.size()) {
final T item = Double.compare(items1.get(i1).volume(), items2.get(i2).volume()) <= 0 ? items1.get(i1++) : items2.get(i2++);
if(predicate.test(item)) {
result.add(item);
}
}
while (i1 < items1.size()) {
final T item = items1.get(i1++);
if(predicate.test(item)) {
result.add(item);
}
}
while (i2 < items2.size()) {
final T item = items2.get(i2++);
if(predicate.test(item)) {
result.add(item);
}
}
return result;
}
private static <T extends Toy, E extends List<T>> List<T> exclusiveZipBy(final E items1, final E items2, final Predicate<T> predicate) {
final List<T> result = new ArrayList<>();
final Iterator<T> i1 = items1.iterator();
final Iterator<T> i2 = items2.iterator();
while(i1.hasNext() && i2.hasNext()) {
final T item1 = i1.next();
final T item2 = i2.next();
final T item = Double.compare(item1.volume(), item2.volume()) <= 0 ? item1 : item2;
if(predicate.test(item)) {
result.add(item);
}
}
while(i1.hasNext()) {
final T item = i1.next();
if(predicate.test(item)) {
result.add(item);
}
}
while(i2.hasNext()) {
final T item = i2.next();
if(predicate.test(item)) {
result.add(item);
}
}
return result;
}
private static <T extends Toy> Predicate<T> createFilterByCapacity(double capacity) {
final double[] counter = { capacity };
return item -> {
return Double.compare((counter[0] -= item.volume()), 0) >= 0;
};
}
private static <T extends Toy, E extends Collection<? extends T>> String mapToString(final E itemList) {
return itemList.stream()
.map(Toy::volume)
.map(String::valueOf)
.collect(joining(", ", "{ ", " }"));
}
private static <T extends Toy, E extends List<T>> List<T> generateList(int min, int max, int limit, final Function<Double, T> mapper) {
return ThreadLocalRandom.current()
.doubles(min, max)
.limit(limit)
.boxed()
.map(mapper)
.collect(toList());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment