class ParentItem {
String itemName; //I want to get this property for all the objects in hierarchy
Integer itemCode;
List<ParentItem> childItem;
}
I want to get the names of the All Items(ParentItem name, ChildItem name, GrandChildItemName) using streams, how to achieve this? Assume the ChildItem also has a Child which means the ParentItem has a GrandChild! So there are 3 levels of Nesting. How to achieve this?
Try the following approach to recursively flatmap the child streams:
Stream<ParentItem> flatMapChildren(ParentItem item ) {
return Stream.concat( //flatMap replaces the item in the stream so we need concat() to keep it
Stream.of(item), //create a 1-element stream for the item that gets replaced
item.childItem.stream() //create a stream for the children
.flatMap(YourClass::flatMapChildren) //recursively add their children
);
}
Then use that on your top level stream:
List<ParentItem> topLevel = ....;
Stream<String> streamOfAllNames =
topLevel.flatMap(YourClass::flatMapChildren)
.map(ParentItem::getName);
Note: the implementation doesn't contain null checks etc. for simplicity reasons. Add those in your actual code.
public static void main(String[] args) {
ParentItem grandpa = new ParentItem();
List<String> listOfItemNames = Stream.of(grandpa)
.flatMap(Main::loadChildRecursively)
.map(ParentItem::getItemName)
.collect(Collectors.toList());
listOfItemNames.forEach(System.out::println);
}
private static Stream<ParentItem> loadChildRecursively(ParentItem parent) {
if (parent.getChildItem() != null && parent.getChildItem().size() > 0) {
return Stream.concat(parent.getChildItem().stream().flatMap(Main::loadChildRecursively), Stream.of(parent));
} else {
return Stream.of(parent);
}
}
An important thing to keep in mind is, when calling the recursive function always add / include your parent object, otherwise you'll end up only having the lowest level of children and no parents.
I have a class City
public final class City {
private final String name;
private final String state;
private final int population;
public City(String name, String state, int population) {
this.name = name;
this.state = state;
this.population = population;
}
public String getName() {
return name;
}
public String getState() {
return state;
}
public int getPopulation() {
return population;
}
#Override
public String toString() {
return "City [name=" + name + ", state=" + state + ", population=" + population + "]";
}
}
And a class that implements Observable (not needed for this). This observable class holds an arraylist List<City> cityList that has the data for all the cities that have been reported.
My class TopFiveCities is supposed to:
"implement a getter method getTopFive() returning a list with the five
top cities (in terms of population) received. The list is sorted from
higher to lower numbers. The returned list must be a copy of the list
kept by the observer"
Aside from just getting the top 5 list, I also need to know how to make a copy of that list from the observer.
This is what I have:
public class TopFiveCities
implements Observer {
// THIS ALSO DOESN'T WORK UNLESS THE LIST IS STATIC
// SO HOW CAN I MAKE A COPY OF THE LIST FROM OBSERVER?
private List<City> list = new ArrayList<>(CensusOffice.cityList);
public List<City> getTopFive() {
Collections.sort(list, new Comparator<City>() {
#Override
public int compare(City o1, City o2) {
return Integer.compare(o1.getPopulation(), o2.getPopulation());
}
});
return list;
}
public void update(Observable observable) {
if (!(observable instanceof Observable)) {
throw new IllegalArgumentException();
}
}
}
With this, when one of the sample outputs should be:
City [name=Chicago, state=IL, population=2746388]
I just receive a list of all the cities, sorted by population from LOWEST to HIGHEST. What I'm doing wrong?
You can just use a Stream, use a Comparator to sort the stream, limit the number of element and convert the elements to a new list:
List<City> top5citiesByPopulation = cities.stream()
.sorted(Comparator.comparing(City::getPopulation).reversed())
.limit(5)
.collect(Collectors.toList());
int order = requestedOrder.equals("asc") ? 1 : -1;
Collections.sort(list, new Comparator<CustomObj>() {
public int compare(CustomObj first, CustomObj scnd) {
return first.getComparableParam().compareTo(scnd.getComparableParam()) * order;
}
});
I just copied and passed this code block from recommended stackover page in the comment. Of you want ascending order simply change it. In your code order will be -1.
Simply you need to multiply by -1.
return Integer.compare(o1.getPopulation(), o2.getPopulation()) * -1;
After this you can sublist it.
You keep the list as global variable it can be reached from update method but it does not change if class is singleton except for update method. Your update method can change it by notifying
In update method you can simply clear and add new list by list.addAll
Since this is a schoolwork assignment, I’ll describe the pieces but let you assemble them into final code.
I have a class "City"
You could more briefly define that class as a record.
City ( String name, String state, int population ) {}
holds an array list "List cityList"
List < City > cities = new ArrayList<>();
getting the top 5 list
Sort the list by using a reverse comparator. You can make a comparator for sorting by using a method reference for the accessor “getter” method. But be aware that records do not use the word “get” by default as their accessor, they use simply the name of the property.
cities.sort( Comparator.comparing( City :: population ).reversed() ) ;
For an unmodifiable list, call List.of or List.copyOf.
List#subset gives you a list with some of the elements of the original. But beware: the resulting list is based on a view of the original list. The subset is not separate and independent. To get a separate list, pass to List.copyOf or pass to the constructor of another List implementation.
List< City > topFivePop = List.copyOf( subset ) ;
This problem doesn't require sorting the whole given list, which will have a time complexity of O(n log n).
Basically, the task is somewhat similar to finding the maximum element in the list that can be done in O(n) time with a single pass through the given list.
The most suitable approach for this problem is a partial sorting, and the best performance that could be achieved is the middle-ground between O(n) and O(n log n).
In order to find 5 maximum elements in a list, we can maintain a collection that will store in sorted order up to 5 previously encountered elements with maximum values.
Elements that are lover than the smallest element in the collection will be discarded automatically if the collection is already of size 5. Only new elements with a value higher than the smallest element's value will trigger reordering of this tiny collection. I.e. the data will be sorted partially instead of sorting the whole data set.
In the implementation below for as collection that will store 5 max elements, I've chosen a PriorityQueue.
According to the documentation it's methods have the following time complexity.
this implementation provides O(log(n)) time for the enqueuing and dequeuing methods (offer, poll, remove() and add); linear time for the remove(Object) and contains(Object) methods; and constant time for the retrieval methods (peek, element, and size).
I.e. adding of a new element and removing the first element both will perform in logarithmic time, and accessing the smallest value in the queue with the method element() with done in O(1) time (almost immediately).
The PriorityQueue is encapsulated inside a generic class, which constructor expects as parameters a Comparator<T> and a desired maximum size of the queue (i.e. a number of max elements that needs to be found).
The queue itself doesn't exposed to the outside classes. Method addItem() processing the given element and getFirstN returns a sorted immutable list.
Comparator in the code below is implemented using the static method comparingInt(). You could also implement Comparator in a "classical way" (pre-Java 8) by providing the behavior for it's abstract method compare() either by using a lambda expression or within an anonymous inner class.
public class FirstN<T> {
private final Queue<T> queue;
private final Comparator<T> comparator;
private final int capacity;
public FirstN(Comparator<T> comparator, int capacity) {
this.queue = new PriorityQueue<>(comparator);
this.comparator = comparator;
this.capacity = capacity;
}
public boolean addItem(T item) {
if (capacity == queue.size() && comparator.compare(item, queue.element()) <= 0) {
return false; // queue is full and the given item is smaller than the lowerest element in the queue
}
if (capacity == queue.size() && comparator.compare(item, queue.element()) > 0) {
queue.remove(); // removing the first element if it's smaller than the given item
}
return queue.add(item); // adding the given item
}
public List<T> getFirstN() {
List<T> result = new ArrayList<>(queue); // creating a list based on a queue
result.sort(comparator);
return List.copyOf(result); // making a copy of the list (returned list is immutable)
}
}
main()
public static void main(String[] args) {
List<City> cities = List.of(
new City("Austin", "Texas", 1028225),
new City("Los Angeles", "California", 3985516),
new City("San Diego", "California", 1429653),
new City("Houston", "Texas", 2325353),
new City("Phoenix", "Arizona", 1759943),
new City("New York City", "New York", 8177025),
new City("San Antonio", "Texas", 1598964),
new City("Philadelphia", "Pennsylvania", 1585480),
new City("San Diego", "California", 1429653),
new City("Chicago", "Illinois", 2671635),
new City("Dallas", "Texas", 1348886));
FirstN<City> top5Cities =
new FirstN<>(Comparator.comparingInt(City::getPopulation), 5);
for (City next: cities) {
top5Cities.addItem(next);
}
List<City> result = top5Cities.getFirstN(); // contains 5 biggest US cities
result.forEach(System.out::println); // printing the result
}
Output (order from lowest to highest)
City [name=Phoenix, state=Arizona, population=1759943]
City [name=Houston, state=Texas, population=2325353]
City [name=Chicago, state=Illinois, population=2671635]
City [name=Los Angeles, state=California, population=3985516]
City [name=New York City, state=New York, population=8177025]
When traversing a tree structure recursively in order to calculate weights and volumes for an entire bill of materials, I run into a ConcurrentModificationException. My approach in pseudocode:
Query initialization: add root node to list of nodes and check if it has any childs.
Progress documentation: Flag the node as visited.
Query childs: Checking for child nodes and if present add to allNodes with a level up flag.
Recursive traversal: Recursively traverse list until no more child elements are found.
I have tried to use iterators to allow myself to expand that array of nodes but ran into the same problem. Slowly running out of ideas here I am grateful for any hint.
NOTE: please forgive me to paste my problem not stating all the context for better readability. Let me know if you need more info.
// Initialization
List<Node> allNodes = new ArrayList<>();
allNodes.add(new Node(input, input, 0, false) // (1)
int counter = 0;
// Method call
getAllNodes(allNodes);
// Query parent for child elements
public void getAllNodes(List<Node> nodes){
for (Node node : nodes) {
if (!node.isVisited()) { // (2)
node.setVisited(true);
String parentId = node.getId();
Product product = QueryUtil.getFirstByIdNo(ctx, parentId, Product.class);
if (isComposite(product)) {
Iterable<Product.Row> rows = product.table().getRows(); // (3)
for (Product.Row row : rows) {
allNodes.add(new Node(parentId, row.getProductListElem().getIdno(), ++counter, false));
--counter;
}
++counter;
// Recursive query of all node elements
getAllNodes(allNodes); // (4)
}
}
}
}
//Node Bean with getters, setters, constructor, toString
#Data
class Node {
String parent;
String id;
int level;
boolean visited;
}
You are getting the error because you are trying to modify the list that you are iterating(reading) over. And this is not allowed in JAVA. [for more explanation check here]
To avoid this you can either get an iterator for your list and then loop over it, but that does not seem like a very good option for the code you have posted above. Thus, I'll recommend using List<Node> allNodes = new CopyOnWriteArrayList<>(); instead of List<Node> allNodes = new ArrayList<>().
I have a hashmap in Java in this form HashMap<String, Integer> frequency. The key is a string where I hold the name of a movie and the value is the frequency of the said movie.
My program takes input from users so whenever someone is adding a video to favorite I go in the hashmap and I increment its frequency.
Now the problem is at one point I need to take the most k frequent movies. I've found that I could use bucketsort or heapsort in this leetcode problem (check the first comment), however I am not sure if it is more efficient in my case. My hashmap constantly updates, therefore I need to call the sorting algorithm again times if one frequency changed.
From my understanding, it takes O(N) time to build the map, where 'N' is the number of movies even with duplicates as it needs to add to the frequency, which gets me 'M' unique movie titles. Would that mean that heapsort will result in O(M * log(k)) and bucketsort O(M) for any given k?
Having a map that sorts on values (the thing you map to) isn't a thing, unfortunately. You could instead have a set whose keys sort themselves on frequency, but given that frequency is the key at that point, you couldn't look up entries in this set without knowing the frequency beforehand which eliminates the point of the exercise.
One strategy that comes to mind is to have 2 separate data structures. One serves to let you look up the actual object based on the name of the movie, the other is to be self-sorting:
#Data
public class MovieFrequencyTuple implements Comparable<MovieFrequencyTable> {
#NonNull private final String name;
private int frequency;
public void incrementFrequency() {
frequency++;
}
#Override public int compareTo(MovieFrequencyTuple other) {
int c = Integer.compare(frequency, other.frequency);
if (c != 0) return -c;
return name.compareTo(other.name);
}
}
and with that available to you:
SortedSet<MovieFrequencyTuple> frequencies = new TreeSet<>();
Map<String, MovieFrequencyTuple> movies = new HashMap<>();
public int increment(String movieName) {
MovieFrequencyTuple tuple = movies.get(name);
if (tuple == null) {
tuple = new MovieFrequencyTuple(name);
movies.put(name, tuple);
}
// Self-sorting data structures will just fail
// to do the job if you modify a sorting order on
// an object already in the collection. Thus,
// we take it out, modify, put it back in.
frequencies.remove(tuple);
tuple.incrementFrequency();
frequencies.add(tuple);
return tuple.getFrequency();
}
public int get(String movieName) {
MovieFrequencyTuple tuple = movies.get(movieName);
if (tuple == null) return 0;
return tuple.getFrequency();
}
public List<String> getTop10() {
var out = new ArrayList<String>();
for (MovieFrequencyTuple tuple : frequencies) {
out.add(tuple.getName());
if (out.size() == 10) break;
}
return out;
}
Each operation is amortized O(1) or O(logn), even the top10 operation. So, if you run a million times 'increment a movie's frequency, then obtain the top 10', with n = # of times we do that, then the worst case scenario is O(nlogn) performance.
NB: Uses lombok for constructors, getters, etc - if you don't like that, have your IDE generate these things.
Given a list of categories with a list of items contained in the categories
//Just example of structure:
List<Category> categories = getCategories();
List<Item> items = category.getItems();
With the Java streaming API how do you do Operation1() on first sub-item in a category, then Operation2() on all items in the category?
I want to do it in the cleanest code. So I try to do it in one stream, or what would be the best way to do it?
If you insist on doing that, this would do the trick:
List<Category> categories = getCategories();
categories.forEach(category -> {
List<Item> items = category.getItems();
IntStream.range(0, items.size()).forEach(i -> {
Item item = items.get(i);
if (i == 0)
operation1(item);
operation2(item);
}
);
});
However, for general readability I would strongly recommend just getting the first element (if present) and doing your operation1 on it, and then iterating through the rest (whether by stream or not).
That said, if you would actually not have lists to begin with but have truly streaming and non-blocking code, there is something to say for this approach. This is also why I didn't add .stream() before the .forEach over categories, you're starting from a list to begin with.
There is really no clean way to perform this, but the following code should do the trick. Using an AtomicBoolean to track whether the first element has been treated or not
List<Category> categories = getCategories();
List<Item> items = category.getItems();
AtomicBoolean bool = new AtomicBoolean(true);
items.forEach(item -> {
if (bool.get()) {
bool.set(false);
operation1(item);
}
operation2(item);
});