Working on the properties of objects in a list?

Given the following code:

public class MyObject { String myProperty; public MyObject(String propertyValue) { myProperty=propertyValue; } } 

and

 public class Main { public static void main(String[] args) { ArrayList<MyObject> objects = new ArrayList<MyObject>(); objects.add(new MyObject("first")); objects.add(new MyObject("second")); objects.add(new MyObject("third")); // Now do Task A and Task B } } 

Now I am looking for a better way to do the following:

Task A: Find all objects where myProperty is "second". There is something like

 ArrayList<MyObject> filteredObjects = objects.findPropertyValue(myProperty, "second") ? 

Task B: Extract the various values ​​of myProperty from the list, that is, I want to get an array that includes ("first", "second", "third") There is something like

 ArrayList propertyValues = objects.getPropertyValues(myProperty) ? 

I know that Task A and B can be solved by going through an ArrayList, but I am wondering if there is a better way / already something built into Eclipse? Thanks for any hint :-)

Please note: I do not want to use external libraries (I am currently developing on android and want my application to be small).

+4
source share
4 answers

If you need the former (task A), it may indicate that the ArrayList not the optimal data structure that you should use. This type of access should force you to consider using Map or MultiMap (implemented in the Apache community collections ).

But ... If you really need such things. Several libraries come in handy.

Recently popular is Guava . Another LambdaJ that seems more specialized:

 // Task A filter(having(on(MyObject.class).getPropertyValue(), equalTo("second")), objects); // Task B convert(objects, new PropertyExtractor("propertyValue")); // or even extract(objects, on(MyObject.class).getPropertyValue()); 

(I did not have the opportunity to compile / run the code that I entered, so please do not be too strict)

+1
source

... but then I will say that I am looking for the best way in java without external libraries?

In this case, loops are best.

You can build a solution based on reflexive access to named fields, but the code is not simple and, of course, does not work.

... so I think my teammates are killing me if I imagine an external library that I use for only one small thing.

Your workmates will tend to kill you for this using reflection. The best way to ensure your survival with your gonads still attached (:-)) is to write loops.

0
source

Eclipse would not directly help you in such a task - it can only help in creating a program - it is not created by itself.

If adding a new library to a project is not an option, you can write your own generic solution. However, I highly recommend that you take a look at adding some shared library such as Guava or Apache Commons, as suggested earlier.

The two tasks you are trying to achieve can be more broadly described as filtering and matching (aka selection, projection). Filtering can be generalized using Predicate, a simple function that returns whether an object should be included in a new collection. The mapping can be achieved using a common function that takes one source object (in your case, MyObject) and returns an object of another type (in your case String).

These plural operations (collection) are more easily supported by languages, some of which are compiled in the JVM, such as python (jython), groovy, and scala. But I assume that this is not an option to use another language for the project.

So, I will demonstrate how this can be achieved in Java, although the syntax is a bit clunkier, since we will use anonymous classes for the predicate and converter.

There is a simple DIY filtering example for What is the best way to filter a Java collection? , so I will use it in this example.

Two interfaces we need:

 public interface Convertor<FROM, TO> { TO convert(FROM from); } public interface Predicate<T> { boolean apply(T type); } 

And the actual "library":

 import java.util.ArrayList; import java.util.Collection; public class CollectionUtils { public static <FROM, TO> Collection<TO> select(Collection<FROM> from, Convertor<FROM, TO> convertor) { Collection<TO> result = new ArrayList<TO>(); for (FROM fromItem: from) { result.add(convertor.convert(fromItem)); } return result; } public static <T> Collection<T> filter(Collection<T> target, Predicate<T> predicate) { Collection<T> result = new ArrayList<T>(); for (T element: target) { if (predicate.apply(element)) { result.add(element); } } return result; } } 

Now we can easily perform two tasks:

 import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; public class Main { public static void main(String[] args) { ArrayList<MyObject> objects = new ArrayList<MyObject>(); objects.add(new MyObject("first")); objects.add(new MyObject("second")); objects.add(new MyObject("third")); // Now do Task A and Task B // Task A: Filter Collection<MyObject> filtered = CollectionUtils.filter(objects, new Predicate<MyObject>() { @Override public boolean apply(MyObject myObject) { return myObject.myProperty.equals("second"); } }); for (MyObject myObject: filtered) {System.out.println(myObject.myProperty);} System.out.println(); // TASK B: Map/Select Collection<String> transforemd = CollectionUtils.select(objects, new Convertor<MyObject, String>() { @Override public String convert(MyObject from) { return from.myProperty; } }); for (String str: transforemd) {System.out.println(str);} } } 

Now it would be very simple to change the predicate to filter other objects or to create different lines or even other types instead of a script: just change the apply () and convert () functions! (Alright, and some generic tips :)).

Disclaimer: the code is not fully verified, just deployed for demonstration, and may have some other problems (for example, allocating an ArrayList for new collections). This is why it is usually best to use proven and debugged third-party libraries!

0
source

Admittedly, this is a bit of an advertisement for my work, but it exactly matches your problem.

First, someone has to do the job. Either you do it yourself, that is, you record the necessary loops yourself, or you have some kind of library for you.

I do not know about the other libs suggested here, but if you want to see http://tbull.org/projects/util4j/ , this is a small lib I wrote myself, and the license allows it to take what you need from the source code and include him to your own source.

This approach uses specially created Grepper and Mapper , so there is no need for reflection. It really is very similar to what Amitay Dobo has already sent, but this lib provides more universal modes of operation, including reading input elements from Iterator and lazy grepping / mapping.

Task A: Find all objects where myProperty is "second". There is something like

 ArrayList<MyObject> filteredObjects = objects.findPropertyValue(myProperty, "second") ? 

It will be done as

 import org.tbull.util.Collections; import org.tbull.util.Grepper; private static class PropertyGrepper implements Grepper<MyObject> { public final String property; public PropertyGrepper(String property) { this.property = property; } public @Override boolean grep(MyObject element) { return element.myProperty.equals(property); } } List<MyObject> filteredObjects = Collections.grep(new PropertyGrepper("second"), objects); 

Task B: Extract the various values ​​of myProperty from the list, that is, I want to get an array that includes ("first", "second", "third"). There is something like

 ArrayList propertyValues = objects.getPropertyValues(myProperty) ? 
 import org.tbull.util.Collections; import org.tbull.util.Mapper; private static class PropertyExtractor implements Mapper<MyObject, String> { public @Override String map(MyObject element) { return element.myProperty; } } List<String> propertyValues = Collections.map(new PropertyExtractor(), objects); 

Disclaimer: This code is not verified. myProperty must be available for this, either being public , or provided by the getter function.

Of course, you can use anonymous inner classes for brevity or publicly use Grepper / Mapper for reuse.

0
source

All Articles