How do I search an array of objects by attribute (Java) - java

Is it possible to search an array of objects in Java by a private attribute with the Array.binarySearch method? I was thinking there must be something similar to the sorting technique, where you create a class that implements Comparator and pass this in to Array.sort, but I can't seem to find anything (maybe there is something where instead of the compareTo method you just return the attribute used in the search)??
To be clear I have an array of anonymous Station objects, and this is passed to another class where I want to search the array for the name of the stations, which can be returned via a getName().
Any help would be much appreciated!

Yes - in fact it uses Comparator, which you specified in your answer!
If you have a look over the implementations of the binarySearch method in the API, you come across binarySearch(T[] a, T key, Comparator c) which:
Searches the specified array for the specified object using the binary search algorithm.
You can implement the Comparator however you like, and so can use it to compare the private attributes alluded to in your question.
Edit responding to comment: The T is a generic parameter, meaning it can be anything, so long as it's the same in every position it appears. In this case, it means that the first parameter must be an array of the second parameter's type. Or in other words, if you're sorting an array of Ts (Stations in your case) then you need to pass in an instance of that class (Station here) to act as the object to compare against. This key argument will always be passed in as one of the arguments to the comparator's compare method.
So I suspect in your case you were passing in a String representing the station name; you should instead pass in an instance of Station which has the appropriate name.

Yes, there's an overload that takes a comparator. Remember that you can only use binarySearch if the array is already sorted.

If the array of stations is not already sorted by the station names, it makes no sense sorting and searching for every query. It is faster to do a linear search in this case. However, if you can sort the array and then perform multiple binary searches, it is worthwhile. Implement a comparator such as the following, and use it for both sorting (Arrays.sort(..)) and searching (Arrays.binarySearch(..)):
private class StationNameComparator implements Comparator<Station> {
public int compare(Station s1, Station s2) {
return s1.getName().compareTo(s2.getName());
}
}
Note that I assume that the names are non-null and unique.

Thanks, eventually got it working using
Arrays.binarySearch(allStations,new Station("nameofstationhere"),new StationCompare())
which is probably a bad way as I'm creating a new Station object for comparison... but it works and not sure how to do it using just the string...

Related

Compare 2 object arrays in java, perform condition and modify list data?

I have 2 lists in java, and I need to validate when there is a match, I set a field of the first list, I tried to do it with streams, but I don't know how to compare the two lists, list don't have same kind of elements I want to do something like this:
public static List<TransactionalityIdDBDTO> getVariationDateRange(List<TransactionalityIdDBDTO> list1,
List<TransactionalityIdDBDTO> list2){
List<TransactionalityIdDBDTO> idDBDTOS= new ArrayList<>();
Iterator prueba=list1.iterator();
while(prueba.hasNext()){
TransactionalityIdDBDTO transactionalityIdDBDTO=(TransactionalityIdDBDTO) prueba.next();
if(transactionalityIdDBDTO.get_id().equals(list2.get_id())){
transactionalityIdDBDTO.setVariation("1232");
idDBDTOS.add(transactionalityIdDBDTO);
}
}
return idDBDTOS;
}
Clase TransactionalityIdDBDTO
public class TransactionalityIdDBDTO extends AbstractDTO {
private TransactionalityDBDTO _id;
private String totalTransaction;
private List<String> idResult;
private String variation;
You can compare lists using equals. e.g
list1.equals(list2);
However,
order is important. If lists contain the same content but in different order they will be considered unequal.
the objects the lists hold must override equals. The criteria for what constitutes two objects of TransactionalityIdDBDTO to be equal are up to you. Based on your code, it seems that id is a good start.
if you plan on using those objects as keys in a map, you must override hashCode too (it's a good idea to do this anyway).
if the lists are not in order but you want to consider them equal, then you should probably sort them first based on the id. You can do that like this.
list1.sort(Comparator.comparing(TransTransactionalityIdDBDTO::get_id));
list2.sort(Comparator.comparing(TransTransactionalityIdDBDTO::get_id));
Objects like String, Integer, and other wrapper classes implement Comparable which means they can be compared to each other of the same type using the above. But instead of get_id which returns a String, say you had get get_Foo. Then the Foo class would need to implement comparable or you would have to provide a more detailed comparator on which to sort.
There are many examples of Comparing objects on the site. I recommend you search them using the [hashCode], [equals], [comparable] and [comparator] tags. Imo, understanding these and how they work are essential for a reasonable working knowledge of Java.

How to override addAll function in Java?

For instance I have two Arraylists with different data types.
ArrayList<Integer> intValues = new ArrayList<Integer>();
intValues.add(1);
intValues.add(2);
intValues.add(3);
ArrayList<String> strValues = new ArrayList<String>();
strValues.add("4");
strValues.add("5");
strValues.add("6");
If both of these lists contained the same data type objects, I would easily call addAll function;
intValues.addAll(intValues2);
But of course if I try to call addAll function with these different type lists, compiler warns me with incompatible types: ArrayList cannot be converted to Collection<? extends Integer> warning.
So I have to create a bad solution like;
for(String s: strValues)
{
intValues.add(Integer.parseInt(s));
}
Is there a better way to do this, I mean, creating a class which implements List, overriding addAll function etc. so I will be able to call;
intValues.addAll(strValues);
And intValues list will contain 1,2,3,4,5,6.
Edit: I really don't want to store String values in an Integer array, I have to deal with some creepy old code at the moment and I need a Collection to hold some differend kinds of classes, trying to create a Constructor for those objects, this integer-string scenario is just a simple way to introduce my problem.
Let me tell you about my current situation with another integer-string like scenario:
Creepy class A is car, it holds car's weight, price, color, engine type.
Creepy class B is watch, it holds watch's still type, movement type, price, lug size etc.
I am trying to create a holder class, so it will hold those classes and adding a few functions (for example, overriding compare method makes the holder class to compare prices of different classes).
Now I think I have to create a HolderHolder class which implements List so I can call holderHolder.addAll(carsList) and holderHolder.addAll(watchesList), and it will hold these as Holder objects and yes, this does not look pretty.
You act as if what you want is self-evident and logical. It really isn't. "4" and 4 are entirely unrelated, and expecting that your list of integers now has a value 4 when you call addAll with "4" is, as a consequence, as bizarre as expecting your list of movies to gain 'Forrest Gump' when you call .addAll(colorsOfTheRainbow) on that, because in your mind, 'green' is so incredibly similar to 'Forrest Gump', that you might as well assume that. (Here, 'green' is "4" and 'Forrest Gump' is 4).
So let's do some work and make this more sensible:
That 'assumption' (that "4" is so similar to 4, that you want .add("4") to just mean that 4 shows up in your list) needs to encoded, explicitly, in your code. Now it makes sense, and now you can write a function that maps Green to Forrest Gump and use it for that example just the same - we've generalized the principle.
What you're really talking about is a mapping function that maps an element of your List<String> (so.. a String) to a type that your target list is of (Integer), and you then want the operation: Take this list. Map every value in it with my mapping function. Then, add all the mapped values to this other list.
That makes perfect sense.
So, write that.
List<Integer> intValues = ...;
strValues.map(Integer::valueOf).forEachOrdered(intValues::add);
Looks like bad smell.
One bad Solution can be an own implementation of an List with Type Object. But than you have to cast and work with the Classes of the primitive types.
I think i every case you have to parse or cast. That cost to much of performance just for easy call of addAll.
I would think about the incoming data and why they have to be the same but in different types?
Edit:
If i get to know it correct. It is a little bit hard to understand without more detailed infos.
But maybe you can write an mapper class to map thoose old creepy classes in one new class an then you can put these new class in an collection and can compare all by overriding equals.
public class CreepyClassMapper
{
public CreepyClassMapper(Car aCar, Watch aWatch)
{
}
#override
private boolean equals(Object obj)
{
// maybe add an instance check
CreepyClassMapper other = (CreepyClassMapper) object;
// do your compare stuff
return true;
}
}
if i were you, i will create a function like this in util class
public void append(ArrayList<Integer> intValues, ArrayList<String> strValues){
}

How to find the minimum element of a matrix of objects in java?

I have a Matrix class that has the following attributes: number of Lines, number of columns and a matrix of Objects.
I have to find the minimum element of the matrix of Objects. How could I do that if I don't know what my Objects will be in JAVA?
You can use either the comparable or comparator functions to, effectively sort arrays of objects by a specific value. You will, depending override the compare to value and select an instance field to make comparisons with.
Use reflection to find out of the objects implement comparable and are all the same type or same base type, and that base type implements Comparable.
if not go thru all the fields, for every field that is a string or a number, compare with corresponding... if its an object go in to that and find strings and numbers. Can make a generic comparator. If a field is a collection then poke in to the type and process similarly. Not an easy task but doable. You could also choose not to go more than x level deep by keeping a current level int that you pass around your stack (if you get in to properties that are objects)

Implementing my own treeset in java

I'm implementing my own java treeset. I think the underlying data structure is a BST and each node in the tree contains Object type data field. However, I stuck at how to compare two Object type data using natural ordering comparator. Is there a compareTo function that compares two objects and return the value of their natural ordering? I'm also thinking using hashcode as index key for each node and do comparison based on that. But it seems that distinct object might have same hashcode. Any advice is appreciated.
instead of BST consider RBT (Red black tree). look at here for more reference.
Now your MyTreeSet can take two kind of objects.
1. Object of java given wrapper class like String, Integer, Long etc Or
2. Object of your own written custom classes.
If your data structure needs to support case 1 one then order can be done easily based on compareTo method which is implemented by all java given wrapper class. You only need to call compareTo method to know which object is greater, equal or lesser than others based on it's return value 0, negative and positive value.
For case 2, that means your MyTreeSet needs to take object of custom classes also then you should implement Comparable interface to your custom classes and write your comparison algorithm there. For example if you want MyTreeSet should take Employee class object then implement Comparable method in Employee class and write implementation of compareTo method based on how emp1 will be compared to emp2. You may want to sort them based on their employee ids.
Hope it helps you.

Java String Array

i have two array
String a[]={"11","02","43","24","05","86","37","28","29","10"};
String b[]={"a","c","f","q","w","x","z","x","s","r"};
i want to sort array a[] in ascending order
and the result may like
String a[]={"02","05","10","11","24","28","29","37","43","86"};
String b[]={"c","w","r","a","q","x","s","z","f","x"};
how can i get result like above using java?
any sorting method available in java?
The easiest way would be to link the 2 pieces of data together in some way instead of having them in separate arrays. Many people have suggested a Map which would work great. Depending on exactly what you are trying to do, I would also consider a new class with 2 variables that implement Comparable. Comparable defines the natural ordering of a class when it is in a Collection (in this instance an array) if Collections.sort is not given a different Comparator to use. It would look something like this:
public class Data implements Comparable{
private String stringOne;
private String stringTwo;
#Override
public int compareTo(Object obj) {
stringOne.compareTo((String)obj);
}
Somewhere else call:
Collections.sort(locationOfDataCollection);
You could then create one Collection of Data and access the other String with a getter method. This implementation also would make it simple in future (see Strategy Design) if in some instances the natural order needed to be overridden with a new Comparator (e.g. sort by stringTwo).
Since you have 2 related sets of data, I would either link these via a Pair<String,String> type object and then into a List<Pair>, or put them into a Map<String,String>.
Perhaps the first solution is more intuitive e.g.
public class Pair implements Comparable<Pair> {
public String first;
public String second;
// equals/hashcode etc.
}
Once they're in a standard Java collection, numerous solutions exist for sorting these. e.g. in the above Pair I've implemented the Comparable<T> interface which the Collections sorting mechanisms will make use of.
There is no methods for directly doing this in Java. You have two options.
1) Define a Map<String, String>, put all the pairs in it (like ("11", "a")). Sort first array (or the keys of the map) and retrieve the elements of the map in that order.
2) Create an object that holds each par, create a List with it, and sort comparing only by the number (implement Comparable or create a Comparator).
One issue you'll need to be aware of is that Strings don't sort according to the same rules as integers. You are likely to be surprised by what you get if you leave the array by which you sort as String.

Categories