Last active
October 25, 2022 23:43
-
-
Save AlexRogalskiy/aafdcf52f0f4e6fcb404ddaddb45d525 to your computer and use it in GitHub Desktop.
Greedy collection of toys
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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