Java Nested filter and Nested Streams - java

class Item {
int id;
List<PriceDetails> priceDetails;
String itemName;
}
class PriceDetails {
int price;
}
I am getting multiple items in a JSON file. I am trying to filter priceDetails with empty price (not the items, just removing all the priceDetails in the list with empty price)
I am able to write Java code and its working as expected, but I don't know how to write using Java Streams. Can someone help me?
Thanks in advance.
Java Code :
public static List<Item> filterByEmptyPrice(List<Item> items) {
List<Item> result= new ArrayList<>();
for(int i=0;i<items.size();i++) {
List<PriceDetails> temp= new ArrayList<>();
for(int j=0;j<items.get(i).PriceDetails.size();j++) {
if(nonNull(items.get(i).PriceDetails) && nonNull(items.get(i).priceDetails.get(j).priceDetails.price)) {
temp.add(items.get(i).priceDetails.get(j));
}
}
items.get(i).priceDetails= temp;
result.add(items.get(i));
}
return result;
}

Your filterByEmptyTicketPrice() method doesn't compile with the Item and PriceDetails model you gave.
The correct loop based implementation would be:
public static List<Item> filterByEmptyTicketPrice(List<Item> items) {
List<Item> result = new ArrayList<>();
for (Item item : items) {
List<PriceDetails> temp = new ArrayList<>();
for (PriceDetails priceDetails : item.priceDetails) {
if (nonNull(priceDetails.price)) {
temp.add(priceDetails);
}
}
// bug: you mutate your method input here
item.priceDetails = temp;
result.add(item);
}
return result;
}
Also, as noted above, you're mutating the input items. The correct way to do this with streams and without mutating the input would be:
public static List<Item> filterByEmptyTicketPrice(List<Item> items) {
return items.stream()
.map(item -> new Item(filterPrices(item.priceDetails)))
.collect(Collectors.toList());
}
static List<PriceDetails> filterPrices(List<PriceDetails> priceDetailsList) {
return priceDetailsList
.stream()
.filter(priceDetails -> priceDetails.price != null)
.collect(Collectors.toList());
}
This example assumes you've added a new Item constructor such as:
public Item(List<PriceDetails> priceDetails) {
this.priceDetails = priceDetails;
}
As others mentioned, you should update the model to use getters to access priceDetails and price making them private in your Item and PriceDetails classes.

Related

Get all leaves elements of a recursive nested structure data in Java [duplicate]

This question already has answers here:
How can I get all leaf nodes of a tree?
(2 answers)
Closed last year.
How can I get all leaves elements of a recursive nested structure data?
public class Item {
private String id;
private List<Item> items;
}
Exemple:
A
- AA
- aa1
- AB
- ab1
- abab1
- a1
Result
In the result I need to get only the following list of elements
[aa1, abab1, a1]
Adapt Item like this:
public static class Item {
private final String id;
private final List<Item> items;
public Stream<Item> getLeaves() {
if (items == null || items.isEmpty()) {
return Stream.of(this);
}
return items.stream()
.flatMap(Item::getLeaves);
}
}
Which you can then use as:
final var item = new Item(
"A",
List.of(
new Item("AA",
List.of(new Item("aa1"))
),
new Item("AB",
List.of(new Item("ab1",
List.of(new Item("abab1")))
)
),
new Item("a1")
)
);
final var leaves = item.getLeaves()
.map(Item::getId)
.collect(Collectors.toList());
System.out.println(leaves);
Note: constructors and getters are omitted for brevity
You can do it quite easily in a recursive fashion:
public static List<Item> findLeaves(Item rootItem){
List<Item> leaves = new ArrayList<>();
recursivelyCollectLeaves(leaves, rootItem);
return leaves;
}
private static void recursivelyCollectLeaves(List<Item> leaves, Item actualItem){
if(actualItem.getItems().isEmpty()){
//No children, the actual item is a leaf
leaves.add(actualItem);
}
else{
for(Item child : actualItem.getItems()){
recursivelyCollectLeaves(leaves, child);
}
}
}
PS: In order to make this code work, please note that I added getters to the Item class.
Try adding this method to the class:
public List<Item> getLeaves() {
ArrayList<Item> list = new ArrayList<>();
if (items.size() == 0) {
list.add(this);
} else {
for (Item item : items) {
list.addAll(item.getLeaves());
}
}
return list;
}
It just checks if itself is a leaf. If it is, it returns itself, if not, it returns all of the leaves of its children.

How to read MultiValue ArrayList in Java

I've defined a arrayList as following
List<List<RiskyPersons>> dataArray = new ArrayList<>();
Here is RiskyPersons Class
public class RiskyPersons {
private SA3Tenant sa3tenant;
private int NumberofPersonInCategory;
public RiskyPersons(){
}
public RiskyPersons(SA3Tenant sa3tenant, int NumberofPersonInCategory) {
this.sa3tenant = sa3tenant;
this.NumberofPersonInCategory = NumberofPersonInCategory;
}
}
Then I've successfully added data and saved in dataArray ArrayList.
Following output is showing the saved ArrayList using SOP(dataArray);
[[RiskyPersons{sa3tenant=Homeless.SA3Tenant#3a7cc6b0, NumberofPersonInCategory=99}]]
I want to read this dataArray ArrayList and display values separately. How do I access "NumberofPersonInCategory" value?
From Java-8 and above one can use stream:
dataArray.stream()
.flatMap(List::stream)
.map(RiskyPersons::NumberofPersonInCategory)
.forEach(System.out::println)
I hope this will help you !
public class RiskyPersons {
private SA3Tenant sa3tenant;
private int NumberofPersonInCategory;
public int getNumberofPersonInCategory() {
return NumberofPersonInCategory;
}
public RiskyPersons(){
}
public RiskyPersons(SA3Tenant sa3tenant, int NumberofPersonInCategory) {
this.sa3tenant = sa3tenant;
this.NumberofPersonInCategory = NumberofPersonInCategory;
}
}
List<Integer> values = dataArray.parallelStream().flatMap(Collection::stream).map(RiskyPersons::getNumberofPersonInCategory)
.collect(Collectors.toCollection(ArrayList::new));
You'll need to iterate it twice as
for (List<RiskyPersons> rp : dataArray) {
for (RiskyPersons o : rp) {
System.out.println(o.NumberofPersonInCategory); // unrelated : but its bad naming convention
}
}

Search an ArrayList Model

I want to get all items that contains the search input based on itemName. In c#, I can use lambda, but I could not find any references for android.
Here is the model class:
public class ModelItem {
public long itemId;
public String itemName;
public double price;
}
Here is my list:
public static ArrayList<ModelItem> items;
I will use the list to get the items. Thank you in advance.
Use below code
public void getAllItems(ArrayList<ModelItem> items, String searchItem) {
for(ModelItem item : items) {
if(item.getItemName().contains(searchItem)) {
// here you are getting item which matches inside your list
}
}
I think you have a listview with items. Now you want to filter them with a search string.
You have to implement Filterable in your custom adapter.
How to filter an adapter
First step, copy items into tempList
private ArrayList<ModelItem> items; // You have data into this list
private ArrayList<ModelItem> tempData = new ArrayList<>();
for (ModelItem item : items) {
tempData.add(item);
}
This is to filter items based on query
public void filter(String query) {
items.clear();
if (query.length() > 0) {
for (ModelItem currItem : tempData) {
// Add data into list, if item is having query string
if (currItem.getItemName().toLowerCase().contains(query)) {
mData.add(currItem);
}
}
} else {
// Adding all the items, if query is empty
for (ModelItem item : tempData) {
items.add(item);
}
}
notifyDataSetChanged(); // notify the changes, if you are using an adapter.
}
hey i got a example for your requirement in github, you need to use QueryTextListener in main class, then setFilter to adapter as given in example
please check this link:https://github.com/Wrdlbrnft/Searchable-RecyclerView-Demo

Why aren't my variables pointing to the same array?

I have two classes. One that has the array (ArrayStorage) and the other (ArrayConsumer) has just a variable that will act as a simple reference to an array.
I add a new element to the array using $my_array. Then I check to see if the new element is visible in the $obtained_array. But the test fails because it cannot find the new element. They act like they were different arrays. Shouldn't they point to the same array?
public function testArrayMadness() {
$arrayStorage = new ArrayStorage();
$my_array = $arrayStorage->getArray();
$arrayConsumer = new ArrayConsumer($my_array);
$obtained_array = $arrayConsumer->getArray();
$my_array[3]='c';
$this->assertContains('c', $obtained_array);
}
}
class ArrayStorage {
private $my_array=[1=>'a',2=>'b'];
function getArray() { return $this->my_array; }
}
class ArrayConsumer {
private $obtained_array;
function __construct($array) { $this->obtained_array=$array; }
function getArray() { return $this->obtained_array; }
}
Update:
I did the same on test in Java, it gives me an indexOutOfBoundsException. Does that mean both php and java works the same way in this aspect or is there something wrong with my code?
#Test
public void testArrayMadness() {
ArrayStorage arrayStorage = new ArrayStorage();
List<String> my_list = arrayStorage.getList();
ArrayConsumer arrayConsumer = new ArrayConsumer(my_list);
List<String> obtained_array = arrayConsumer.getList();
my_list.add("c");
assertEquals("c", obtained_array.get(3));
}
}
class ArrayStorage {
private List<String> my_list;
public ArrayStorage() {
my_list = new ArrayList<>();
my_list.add("a");
my_list.add("b");
}
public List<String> getList() { return my_list; }
}
class ArrayConsumer {
private List<String> obtained_list;
public ArrayConsumer(List<String> list) {
this.obtained_list = list;
}
public List<String> getList() { return this.obtained_list; }
}
PHP arrays are not objects, they are assigned by value:
$a = [1,2,3];
$b = $a;
$b[2] = 99;
print_r($b); // 1,2,99
print_r($a); // 1,2,3
A workaround is to use reference signs & (a bad idea generally) or ArrayObjects:
$a = new ArrayObject([1,2,3]);
$b = $a;
$b[2] = 99;
print_r($b); // 1,2,99
print_r($a); // 1,2,99
return reference array using & operator
something like return &$this->my_array;

Returning a specific element from an ArrayList but getting type mismatch error?

I'm currently in my second semester learning Java and for this project we're supposed to be using ArrayLists, enhanced for-each loops and linear search together. For the project I'm creating a task manager and with this method I want to be able to search the ArrayList for dates and then return the entire task with the correct date. I'm getting this error from the highlighted line below "Type mismatch: cannot convert from Task to ArrayList" Due to the assignments guidelines this method has to return it as an ArrayList, what am I doing wrong? and how can I fix it?
public ArrayList<Task> findTasksByDate(Date date) {
while(i<taskMan.size()); {
for (Task element: taskMan) {
if (date.equals(taskMan.get(i).getDueDate())) {
return taskMan.get(i);//error with this line
}
return null;
}
i++;
}
}
To return an ArrayList, you'll need to declare a local ArrayList, add the element to the list, then return the list. Like this:
public ArrayList<Task> findTasksByDate(Date date) {
ArrayList<Task> returnList = new ArrayList<Task>();
while(i<taskMan.size()); {
for (Task element: taskMan) {
if (date.equals(taskMan.get(i).getDueDate())) {
returnList.add(taskMan.get(i));
return returnList;
}
return null;
}
i++;
}
}
Your method declaration:
public ArrayList<Task> findTasksByDate(Date date) {
You're returning a Task, not an ArrayList of Tasks.
Change it to:
public Task findTasksByDate(Date date) {
Your method is returning ArrayList but you want to return a Task. So an Element of the Array.
Your Method should return Task insted of ArrayList
or
Create a new ArrayList and add the return Item to this new list.
public ArrayList<Task> findTasksByDate(Date date) {
while(i<taskMan.size()); {
for (Task element: taskMan) {
if (date.equals(taskMan.get(i).getDueDate())) {
ArrayList<Task> returnList = new ArrayList<>(); // create new list.
returnList.add(taskMan.get(i));//add
return returnList; // return the new collection
}
return null;
}
i++;
}
}

Categories

Resources