dynamic filtering of java object - java

I have following java object
Obj:
----
String id;
List<A>;
A:
--
String A_ID;
String A_PROPERTY;
What I am looking for is to be able to search in a given object. ex: search in a list where A.A_ID = 123
I need to dynamically pass
A_ID = 123
and it would give me
A_Property
I know I could search through a list through iterator, but is there already frameworks out there which lets you do this?
thanks

lambdaj is a very nice library for Java 5.
For example:
Person me = new Person("Mario", "Fusco", 35);
Person luca = new Person("Luca", "Marrocco", 29);
Person biagio = new Person("Biagio", "Beatrice", 39);
Person celestino = new Person("Celestino", "Bellone", 29);
List<Person> people = asList(me, luca, biagio, celestino);
it is possible to filter the ones having more than 30 years applying the following filter:
List<Person> over30 = filter(having(on(Person.class).getAge(), greaterThan(30)), people);

Something like Quaere. From their site:
Quaere is an open source, extensible framework that adds a querying syntax reminiscent of SQL to Java applications. Quaere allows you to filter, enumerate and create projections over a number of collections and other queryable resources using a common, expressive syntax.

why do you need a framework? how about
public String lookupPropertyById(String id)
{
for (A a : myList)
{
if (id.equals(a.id))
return a.property;
}
return null; // not found
}

Hashmap if you only search by one property which has the same type for every inputed object. For example, a string.
The object 1 has the string "Obj1" for key and the second object has the string "Test2"
for key. When you use the get method with the parameter "Obj1", it will return the first object.
P.S. It's really hard to read your "pseudo-code".

Using a hashmap.
Map<String,A> map = new HashMap<String,A>();
A a = new A();
a.id = "123";
a.property="Hello there!";
map.put( a.id , a );
Later
map.get( "123"); // would return the instance of A and then a.property will return "Hello there!"

Related

Java Group Objects in Custom Manner

I have a list of objects that are returned from an external API and each object looks like this:
public class Item {
public String id;
public int processingType;
public String appliedToItemId;
public Float chargeAmount;
}
Objects with a processingType value of 1 need to be "applied" to another object which will have a processingType of 0. The objects are linked with appliedToItemId and id. Once the objects are grouped then I would like to be able to merge them into one object.
This is something I could do with LINQ in C# but wanted to learn if it would be possible with streams introduced in Java 8.
C# would be something like this:
// seperate out items into two lists (processingTypeOneItems, processingTypeTwoItems)
...
// join items
var joinedItems =
from i in processingTypeTwoItems
join j in processingTypeOneItems on i.id equals j.appliedToItemId into gj
from item in gj.DefaultIfEmpty()
select new { id = i.id, chargeAmount = i.chargeAmount, discountAmount = item?.chargeAmount ?? 0 };
As can be seen, the items are matched on i.id == j.appliedToItemId and then the objects are merged into an object of anonymous type. I am really confused since most examples I have seen simply group by one attribute.
Is it possible in Java to group in this custom manner where the value of one attribute is compared to the value of another attribute?
var joinedItems = processingTypeTwoItems.stream()
.map(item -> new Item() {{
id = item.id;
processingType = item.processingType;
appliedToItemId = item.appliedToItemId;
chargeAmount = processingTypeOneItem.stream().filter(i -> i.appliedToItemId.equals(item.id)).findFirst().orElse(new Item() {{chargeAmount = 0.0f;}}).chargeAmount;
}}).collect(Collectors.toList());

Vaadin DropDown/Select/Spinner best practice?

I am looking at the Vaadin components and it seems like the "favoured" Select-component in Vaadin does not run on indexing.
Using this code:
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("A");
Select<String> select = new Select<>();
select.setItems(list);
So when I have the following list:
A
B
A
And I choose the third option, A, it would appear as the first option, also A, in the list. Is there a Vaadin component or library with java implementation which runs on indexed values? or has there been a workaround.
How would the end user distinguish those identical options?
The Select component relies on the equals and hashCode methods to distinguish items. In your case, the two strings are equal to each other, and as such they are the same from the component's point of view.
So if you have a valid use case for this, you will have to pass items where equals is properly implemented for the use case.
There are several ways to do this: making a custom class, passing in a map of values, passing in an enum etc. In all cases you will probably want to use a custom item label generator.
With a map, it would look something like this:
Map<Integer, String> values = new HashMap<>();
values.put(1, "A");
values.put(2, "B");
values.put(3, "A");
Select<Integer> select = new Select<>();
select.setItems(values.keySet());
select.setItemLabelGenerator(values::get);
add(select);
Or with an enum, as cfrick suggested:
enum Option {
FIRST_A("A"), B("B"), SECOND_A("A");
private final String name;
Option(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
...
Select<Option> select = new Select<>();
select.setItems(Option.values());
select.setItemLabelGenerator(Option::getName);
add(select);

HashSet contains substring

I have a HashSet of Strings in the format: something_something_name="value"
Set<String> name= new HashSet<String>();
Farther down in my code I want to check if a String "name" is included in the HashSet. In this little example, if I'm checking to see if "name" is a substring of any of the values in the HashSet, I'd like it to return true.
I know that .contains() won't work since that works using .equals(). Any suggestions on the best way to handle this would be great.
With your existing data structure, the only way is to iterate over all entries checking each one in turn.
If that's not good enough, you'll need a different data structure.
You can build a map (name -> strings) as follows:
Map<String, List<String>> name_2_keys = new HashMap<>();
for (String name : names) {
String[] parts = key.split("_");
List<String> keys = name_2_keys.get(parts[2]);
if (keys == null) {
keys = new ArrayList<>();
}
keys.add(name);
name_2_keys.put(parts[2], keys);
}
Then retrieve all the strings containing the name name:
List<String> keys = name_2_keys.get(name)
You can keep another map where name is the key and something_something_name is the value.
Thus, you would be able to move from name -> something_something_name -> value. If you want a single interface, you can write a wrapper class around these two maps, exposing the functionality you want.
I posted a MapFilter class here a while ago.
You could use it like:
MapFilter<String> something = new MapFilter<String>(yourMap, "something_");
MapFilter<String> something_something = new MapFilter<String>(something, "something_");
You will need to make your container into a Map first.
This would only be worthwhile doing if you look for the substrings many times.

JDBC Template - One-To-Many

I have a class that looks like this. I need to populate it from two database tables, which are also shown below. Is there any preferred way to do this?
My thought is to have a service class to select a List<> via a ResultSetExtractor from a DAO. Then do a foreach on that list, and select a List<> of emails for the individual person via another ResultSetExtractor, and attach it from with the foreach loop.
Is there a better way, or is this as good as it gets?
public class Person {
private String personId;
private String Name;
private ArrayList<String> emails;
}
create table Person (
person_id varchar2(10),
name varchar2(30)
);
create table email (
person_id varchar2(10),
email varchar2(30)
);
This is best solved by an ORM. With JDBC, you have to do by hand what an ORM would do for you. Executing N + 1 queries is very inefficient. You should execute a single query, and build your objects manually. Cumbersome, but not hard:
select person.id, person.name, email.email from person person
left join email on person.id = email.person_id
...
Map<Long, Person> personsById = new HashMap<>();
while (rs.next()) {
Long id = rs.getLong("id");
String name = rs.getString("name");
String email = rs.getString("email");
Person person = personsById.get(id);
if (person == null) {
person = new Person(id, name);
personsById.put(person.getId(), person);
}
person.addEmail(email);
}
Collection<Person> persons = personsById.values();
I was looking for something similar, and although the answer is perfectly valid I went with this nice library instead https://simpleflatmapper.org/0203-joins.html
It also integrates perfectly with Spring boot.
main advantage is that you have a clean repository layer, it uses your pojo and makes refactoring much easier, and like hibernate you can still map deep nested and complex one to many and still be in control of what is executed.
It also has a nice jdbctemplate CRUD and Java 13 finally brings support for multi-line string literals which is very good for sql statements readability. hope this helps someone :)
In my case, I had to use the LinkedHashMap to keep the query result ordered by the position field.
From JavaDoc:
LinkedHashMap: "This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order). Note that insertion order is not affected if a key is re-inserted into the map."
HashMap: "This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time".
TIP: using the getOrDefault method eliminates the extra check for nullable object.
public List<BucketDto> findAll() {
var sql = """
SELECT
b.uuid bucket_uuid, b.position bucket_position, b.name bucket_name,
c.uuid card_uuid, c.position card_position, c.name card_name
FROM bucket AS b
LEFT JOIN card AS c ON c.bucket_id = b.id
ORDER BY b.position ASC, c.position ASC
""";
return jdbcTemplate.query(sql, rs -> {
Map<Double, BucketDto> resultMap = new LinkedHashMap<>();
while (rs.next()) {
var position = rs.getDouble("bucket_position");
var bucketDto = resultMap.getOrDefault(position, new BucketDto(
UUID.fromString(rs.getString("bucket_uuid")),
position,
rs.getString("bucket_name")));
if (Optional.ofNullable(rs.getString("card_uuid")).isPresent()) {
bucketDto.addCard(new CardDto(
UUID.fromString(rs.getString("card_uuid")),
rs.getDouble("card_position"),
rs.getString("card_name")));
}
resultMap.put(position, bucketDto);
}
return new ArrayList<>(resultMap.values());
});
}

Convert a List<String> to a List<MyObject>, where MyObject contains an int representing the order

Is there a pattern, or built in function I am missing or shall I just loop through like so
public List<MyObject> convert(List<String> myStrings){
List<MyObject> myObjects = new ArrayList<MyObject>(myStrings.size());
Integer i = 0;
for(String string : myStrings){
MyObject myObject = new myObject(i, string);
myObjects.add(object);
i++;
}
return myObjects;
}
Its because I need to persist the list to a database and retain the ordering.
You can use Guava:
List<MyObject> myObjects = Lists.transform(myStrings,
new Function<String, MyObject>() {
private int i = 0;
public MyObject apply(String stringValue) {
return new MyObject(i++, stringValue);
}
});
Really it just brings the iteration into the library though. In terms of actual code written, it will be about the same until closures are introduced with Java 8.
However, you should know that making the function stateful like this (with i) is bad form since now the order in which it's applied to the list is important.
Closures and lambdas that are coming in Java 8 should allow Java to have things like Mapper and Reducer functions(as in MapReduce). In fact, if you are following the latest developments from Project Lambda you would see lots of sample lambda code operating on collections.
e.g.
Collections.sort(people,
#{ Person x, Person y -> x.getLastName().compareTo(y.getLastName()) });
But until then the code you posted in your question should suffice.
Your code will work fine. It's a little bit cleaner if you are using groovy because you could just do something like:
def i = 0;
def myObjects = myStrings.collect {str -> new MyObject(i++, str);}
Or Guava like Mark Peter's code. But, if you don't want to switch languages or import a new library, your code is perfectly fine.
I'll echo glowcoder's comment above and wonder why you need to transform the List -- which by definition has ordering information -- instead of simply persisting data to the database directly.
That said, I'll still offer a concise code snippet:
for (final String string : myStrings) {
myObjects.add(new MyObject(myObjects.size(), string));
}

Categories