How to use indexOf() in an ArrayList on Android? - java

I have a problem and it's that I try to get the position of an item in an ArrayList called cars.
Car car = new Car(int idcar, String model, String brand); //Here it's an example
ArrayList<Car> cars = new ArrayList<Car>();
And suppose that I have 5 cars in the ArrayList and I want to get the information of the car number 3 so I tried to get the position with the function indexOf() but it always returns me the value -1.
I know that the value -1 it's when it didn't found any car in the arraylist that it's equals to the car that I use in the function. Could it be because idcar is null when I use the second constructor and try to find the object with indexOf()? I use the function like this:
int position = cars.indexOf(car);
I think it's because I have 2 constructors of the class Car. One with idcar, model and brand and another with just model and brand. I did that because if I don't know the id of the car, I can't use the car in the function so it's an infernal loop and I don't have any idea how to end it.
It's connected to a database that save all the cars that you insert into the arraylist and it's why I need the id, just because if I enter 7 cars one day, close the application and run it again, I won't know the id (that it's the position in the arraylist) of this car and I won't be able to delete one of them, for example.
Of course I have all get's and set's methods in the class Car to get or set all the information when I have inicialized the object Car.
I expect it could be understood clearly.
Thank you very much!

If you haven't implemented Car's equals() method, you have to be sure that you are passing exactly the same instance of Car to the indexOf() method as the instance that is contained by the list.
This is because indexOf() uses contained objects' equals() method and equals() default implementation is just a == comparison.
It'd make sense to implement Car's equals() method.

Related

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){
}

Can JUNG library make edges based on predefined properties?

I have some data of let’s say type Person. This Person has a phone-number property but also a calling and a called phone-number properties.
class Person {
String id;
String displayName;
String phoneNr;
String callingNr; // or List<String> callingNrs;
String calledNr; // or List<String> calledNrs;
}
What I want, is I put a bunch of those Person objects in a Graph instance and than render the relationships on a view. Ideally the components drawn on the view are interactive, meaning you can click on a node/vertex that highlight the edges (and maybe more).
I tried JUNG, but in the documentation, I see some examples that I have to, kind of, define the relationships between Person objects myself, like below:
Graph.addEdge("edge-name", personA.phoneNr, personB.phoneNr);
I’m new to JUNG, but maybe there’s a way to tell JUNG about the properties of Person and that JUNG knows how to connect them?
Is this possible with JUNG? Or do I need another type of library, if yes, than can someone please provide me one I can use?
Here is what I would do:
Make a java.util.Map of each person's phone number (key) to an instance of the Person (value). That is your reverse number lookup.
Populate your reverse number lookup map by iterating over your collection of people using the PhoneNr as the key and the Person instance as the value.
Next, I would create an edge class 'PhoneCall' that contains information like 'time of call' and 'duration of call' (more or less info, depending on what you have available).
To add edges to your graph, iterate over your collection of Person instances, and for each Person, iterate over the collection of calling numbers. For each calling number, use the reverse number lookup map to get the person calling and make a directed edge to connect the calling person to the current person.
Do something similar for the each Person's collection of called numbers.
Your graph nodes will be Person instances, and your edges will be PhoneCall instances that connect one Person to another. Be sure to add an equals and hashCode method to your Person class and to your PhoneCall class so that they will work properly (and duplicates will be detected and hopefully ignored).
Hope this helps!

Referencing an Object Inside an Object

I am creating a game in Java and need to create a list of all of the rooms in it.
I have a 'Rooms' class that has the code for the room, i.e. room name, items in the room etc.
In the Room class I want to have a static ArrayList that has all of the room objects in the whole game in there. This is needed for a method I am working on.
I have created an ArrayList field:
private static ArrayList<Rooms> listOfRooms = new ArrayList<Rooms>();
In the initialisation of each instance of Rooms, I wish to add that instance to the listOfRooms ArrayList.
I assume you start with listOfRooms.add(), but what would you actually put in the parameter to add the current object to the list of Rooms objects?
You'd add this to the list; this being a reference to the current object (a Room in this case) being worked on:
listOfRooms.add(this);
Note though, having listOfRooms as a static member of the class is a bad idea. With this setup, you can only ever have one list, and anyone can alter the list however they want since it's public.
It would likely be much better to create something like a Hotel class and make it a member of that:
class Hotel {
ArrayList<Rooms> listOfRooms = new ArrayList<Rooms>();
}
Now you can at least have multiple hotels if necessary with separate lists of rooms, and to modify the rooms, code would at least require a reference to the hotel.
Adding to what Carcigenicate said, it's always better to have more abstraction in object oriented programming.
For example, Hotel object has a Floor ArrayList in it. Each Floor object contains ArrayList of Room and so on.

How would I allow the user to add, edit, delete groups of Lists? Such as a classroom, cabin, etc

I was hoping someone could tell me if I'm even going about this the right way, or if what I'm doing is even possible.
My end goal is to create a program where you can create cabins, create campers, and assign them to a cabin.
What I thought of was allowing the user to create a new ArrayList by having a method called that does such. I would create a Camper class where it has the variables such as name, age, gender, etc...
Then I would write a method that looked something like this....
public static void userCreatesList(){
ArrayList<Camper> cabin = new ArrayList<Camper>();
}
The problem is, the method works when I add items to the list and have it print out as each time it prints a different list when calling the method, however, what I cannot figure out how to do is to call a previous list again as every list here will have the same variable or object name.
So, if I created say three cabin lists all together by calling this method three times, how would I assign a person to a particular cabin if they all end up having the same variable name?
It has to be a program where the user can create the list and I didn't have to declare a number of lists with a different variable name, because each camp may have a different number of cabins, and they have to be able to make their own list?
If what I'm doing is not possible and I need to be using another type of object besides a list to do this, please just tell me and I'll research how to use that object.
I've searched all over how to create a new group, a new set, etc.. and I cannot find anything relevant to what I'm trying to do that can explain this.
I want them to be able to give that group a name, such as "Red Cabin", "Blue Cabin", "Cabin 1", "Cabin 12", etc....
For this I would recommend to use Map, with group name as a key and ArrayList as value.
private static Map<String, ArrayList<Camper>> cabinMap = new HashMap<String, ArrayList<Camper>>();
public static void userCreatesList(String groupName){
ArrayList<Camper> cabin = new ArrayList<Camper>();
cabinMap.put(groupName, cabin);
}
Later you can access to the certain group from this map by name and add members to it.

Java collection for this use case

Let's say we have a bunch of Car objects.
Each Car has some distinguishing properties e.g. manufacturer, model, year, etc. (these can be used to create distinct hashCodes).
Each car has a List of PurchaseOffer objects (a PurchaseOffer object contains pricing\retailer info).
We receive Lists of Cars from several different sources, each Car with a single PurchaseOffer.
Thing is, these lists may overlap - a Car can appear in more than one list.
We wish to aggregate the lists into a single collection of Cars where each Car holds all encountered PurchaseOffers for it.
My Problem is choosing what to collection to use in this aggregation process:
Feels natural to use java.util.HashSet for holding our cars, that way when going over the different lists of Cars, we can check if a car already exists in the Set in amortized O(1),
however - you cannot retrieve an element from a Set (in our case - when we go encounter a Car that already exists in the Set - we would have liked to retrieve that Car from the Set based on its identifying hashCode and add PurchaseOffers to it).
I can use a HashMap where each Car's hashCode maps to the actual Car object, but it probably isn't the school-book solution since it is unsafe - I would have to make sure myself that every hashCode maps to a Car with that hashCode - there could be inconsistency.
Of course, can make a designated data structure that guarantees this consistency - Shouldn't one already exist ?
Can anyone suggest the data-structure I am after, or point out a design mistake ?
Thanks.
Since this is a many-to-many relationship, you need a bi-directional multi-map. Car is the key for the first one, with a List of PurchaseOrder as the value. The PurchaseOrder is the key for the second one, with a List of Cars as the value.
The underlying implementation is two HashMaps.
Put an API on top of it to get the behavior you need. Or see if Google Collections can help you. It's a combination of a BiMap and two MultiMaps.
I think that you really do need (at least) a HashMap<Car, List<PurchaseOffer>> ... as suggested by #Andreas_D
Your objection that each Car already has a List<PurchaseOffer> is beside the point. The list in the HashMap is the aggregate list, containing all PurchaseOffer objects from all Car objects that stand for the same physical car.
The point of creating a new list is to avoid changing the original lists on the original Car objects. (If that was not a concern, then you could pick one instance of Car from the set that represent a physical car, and merge the PurchaseOffer objects from the others into that list.)
I'm not entirely sure why #duffymo suggested a bi-directional map between, but I think it is because the different Car objects from different sources may have complementary (or contradictory) information for the same physical car. By keeping all instances, you avoid discarding information. (Once again, if you are happy to discard mutate and/or discard information, you could attempt to merge the information about each individual car into a single Car object.
If you really didn't care about preserving information and were prepared to merge stuff willy-nilly then the following approach would probably work:
HashMap<Car, Car> map = new HashMap<Car, Car>(...);
for (Car car : carsToBeAggregated) {
Car master = nap.get(car);
if (master == null) {
map.put(car, car);
} else {
master.offers.addAll(car.offers);
// optionally, merge other Car information from car to master
}
}
You should NOT be trying to use the Car.hashCode() as a key for anything. Hashcode values are not unique identifiers: there is a distinct possibility that two different cars will end up with the same hashcode value. If you attempt to use them as if they were unique identifiers you'll get into trouble ...
The basic datastructure should be a HashMap<Car, List<PurchaseOffer>>. This allows for storing and receiving all offers for one selected car.
Now you may have to find a suitable implementation for Car.equals() to assure, that "cars" coming from different source are really the same. What about basing equals() on a unique identifier for a real world car (VIN)?
I would prefer to use a HashMap<Car, List<PurchaseOffer>>, as suggested before (Andreas, Stephen), mainly if the Car object does not hold the list of PurchaseOffers.
Otherwise I would consider using a HashMap<Car, Car> or, better IMO, a HashMap<ID, Car> if there is an unique ID for each Car.
It can not simply map the Car's hashCode to the Car, as mentioned in the question, since distinct Cars can have the same hashCode!
(Anyway, I would create an own class for storing and managing the Cars. This would contain the HashMap, or whichever - so it's easy to change the implementation without needing to change its interface)
create tout custom class that extends hash
Set, override method contains(Object o) check there os hash code is same or not and return result according, and add object to set of and only if it not containing that object
How about a defining a new custom Aggregation class? Define the hashcode such that the id of the car acts as the key and override the equals() accordingly. Define a custom method for accepting your original car and do a union operation on the lists. Finally store the custom objects in a HashSet for achieving constant time look up.
In purist terms, aggregation is a behavior beyond the scope of a single object. Visitor pattern tries to address a similar problem.
Alternatively if you have a sql datastore, a simple select using group by would do the trick.
Welp, yeah, HashMap<Car, List<PurchaseOffer>> would be perfect if it wasn't for the fact that
each Car contains a List<PurchaseOffer> as a property. Can say that a Car object is composed
of two parts: an identifying part (let's say each car indeed has a unique VIN), and the list of
PurchaseOffers.
In this case split the Car class in two classes - the CarType class with the identifying attributes, and then the list part (maybe both together used by Car). Then use Map<CarType, Lost<PurchaseOffer> for your datastructure (or MultiMap<CarType, PurchaseOffer>).
//alt. 1
List<Offer> offers;
List<Car> cars;
Map<Car, List<Offer>> mapCarToOffers;
Map<Offer, List<Car>> mapOfferToCars;
public void List<Offer> getOffersForCar(Car aCar);
public void List<Car> getCarsForOffer(Offer anOffer);
Alternative 1 would make use of the hashCode() of Car and Offer
//alt. 2
List<Offer> offers;
List<Car> cars;
Map<Integer, List<Offer>> mapCarIdToOffers;
Map<Integer, List<Car>> mapOfferIdToCars;
public void List<Offer> getOffersForCarId(int aCarId);
public void List<Car> getCarsForOfferId(int anOfferId);
Alternative 2 would make use of the hashCode() of Integer. This would allay your concerns about "safety" as the hash codes for Integer objects should not overlap where the values are unique. This incurs the additional overhead of having to maintain unique IDs for each Car and Offer object, however, I am guessing that you probably already have those from your business requirements.
Note, you may choose to use other classes as alternative to ints for ID's (e.g. String).
For both alternatives, implement the Lists with ArrayList or LinkedList - which one is better is up to you to determine based on other requirements, such as the frequency of insertion/deletion vs lookup. Implement the Maps with HashMap - see comments above about how hash codes are used.
As a side note, in our software, we use these both of the above to represent similar types of many-to-many data. Very similar to your use case.
Both alternatives work very well.
Why not use an object database for this? You could store any object graph you wanted, and you'd get a search API with which you could do any relationship/retrieval mechanism you wanted. A simple collection could work, but it sounds like you want a more complex relationship than a collection would provide. Look into db4o (http://db4o.com) - it's very powerful for this sort of thing.

Categories