I think this is an easy question, if I could figure out search terms to describe it. It's similar to Finding all objects that have a given property inside a collection except I just want a Boolean "is it there" result.
Say I have a sorted TreeSet of Cats, each of which has a name, age, food, etc. I have something complicated to do for each potential cat name, but I want to skip it if there already a cat in my TreeSet with that name. I don't care if any of the other attributes match. I obviously can't do if (!AlltheCats.contains(candidateName))... because then I'll have a type mismatch between the string candidateName and the object Cat. But I don't think I can create an object to search for an identical match to, because I don't care about the values for age, food, etc.
What would be an efficient/elegant way to do this?
Create a HashSet of Strings containing names, every time you invoke your method on a cat, check first if it is already in the set, and if it is, skip this cat. Modify this set as you keep going.
(*)This answer assumes you want to invoke the method for one cat [and not 0] with identical name.
Should look something like that:
Set<String> names = new HashSet<String>();
for (Cat c : set) {
if (names.contains(c.getName())) {
continue;
}
names.add(c.getName());
c.foo(); //your method here
}
Related
For a project I am working on in class, I am required to create an ArrayList containing an undefined number of adherents (instances of a class) which all possess different names, Id's, etc. I then have to call on one of them to, for example, change it's Id(using a method like adherent.setId(newId)).
However, with the way my code is setup, all new instances are called the same, and because the number of adherents is undefined, I can't simply use something like
Adherent adherent1 = new Adherent(lastName, firstName, currentYear, currentId);
Adherent adherent2 = new Adherent(lastName, firstName, currentYear, currentId);
Adherent adherent3 = new Adherent(lastName, firstName, currentYear, currentId);
etc... for each of them.
This is the method I am currently using
public static List<Adherent> createAdherent(int currentId, int currentYear, List<Adherent> adherentList) {
Scanner sc = new Scanner(System.in);
System.out.println("Please enter the last name of the new adherent");
String lastName = sc.next();
System.out.println("Please enter the first name of the new adherent");
String firstName = sc.next();
Adherent adherent = new Adherent(lastName, firstName, currentYear, currentId);
adherentList.add(adherent);
adherent.setName(lastName);
adherent.setFirstName(firstName);
adherent.setYearAd(currentYear);
adherent.setId(currentId);
System.out.println(adherent.toString());
return adherentList;
}
I am wondering if there is a way to call on them (use .set or .get method) using something other than their names (maybe a variable) or if there is a way to name them all differently in my createAdherent() method. I have been searching for a couple days and can't seem to find an answer.
Your method is an interesting one. I would consider some refactoring.
First, you're taking in a List, adding an item to it, then returning that List. The return is pointless as you're already adding to the list.
Given the signature of createAdherent(int currentId, int currentYear, List<Adherent> adherentList), you're passing in a List. Instead, consider making your method
public Adherent createAdherent(int currentId, int currentYear) (static if you must)
Then you would call it like this:
adherents.add(createAdherent(1, 2000))
where adherents is the List of Adherent that you were passing in. No need to take a List or return a List, just return the object that you want to add to the List.
From what I understand you want to call an item by name and change its id, but there may be more than 1 item with the same name.
Note: I believe that if you are passing 'lastName' and 'firstName' in the constructor itself, it should update the variable values, with no need to call .setName(lastName) and .setFirstName(firstName)
Returning to your problem, I believe that if you are getting the obj by name to change the id, knowing that there may be more than one with this name, I think this should not happen. What I believe can be done:
Op 1: Prevent the creation of an object with the same name, putting its creation in a loop, validating if there isn't one with that name and, if not, adding it to the array. You can even put a message that there is already one with this name. Or returning an error that will be handled by the caller using a try{ createAdherent(); }catch(Exception e){...}
Op 2: Do not search by name but by id (I believe this is the best option to search for an object, as an id would do just that), but as it is an array you would end up going through it all, which is bad, you could use a Map<Integer, Adherent> to get it by id.
Op 3: If the problem is that you don't know which 'Adherent' was created because the function return is an array(what i don't recomend cause the function name), then you could, inside the 'createAdherent' function, return only the new 'Adherent' (which is kinda like that's his name), and leave it in case it is necessary to get the other values, these are taken by another function, such as:
public static List<Adherent> getAdherents(){
//If you don't want to be able to delete the object from the array externally
return Collections.unmodifiableList(adherentList);
//Or simply
return adherentList;
}
Or use all then.
Hope this helps :)
Your function createAdherent must be better named createAdherentInList as you give the list to update in the parameters. And no need to return the list, as already said, it's already done.
I believe your problem is a more classic one about owning a unique ID for each instance.
Either you decide to generate automatically the ID and never allows an external call to change this ID that will stay unique.
Either this ID is free to be changed and you have no way to distinguish an adherent from another except by its position when it was added . You can retrieve it by it's order of insert : Adherent myList.get(position).
In any case, you need some another functions to retrieve an adherent like:
Adherent findAdherentById(someUniqueId)
list findAdherentByName(someName) // here returns a list as it can have homonyms and you will have to choose one before to be able to change something.
HTH
The instances are not called adherent1, adherent2, etc. Those are only the names of variables, which are only loosely associated with instances of objects.
You can get to your instances from the list as adherentList.get(0), etc.
You can process them all by constructs such as for (adherent : adherentList) ....
There might be better ways to organize the data, but that requires more infomation about what you need to do with it.
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){
}
Lets assume there is a data service that returns instances of the class cat:
class Cat {
int id;
String name;
int iq;
}
I want to hold the instances inside a Set<Cat> that must not hold two cats with the same id. So I need to override the equals and hashcode method to only check for the id.
My question is how can I detect if a cat inside my set requires an update when I receive a new instance from the service with the same id, but different values for name and/or iq? I cannot add the properties to equals or hashcode since then it would be possible that the Set holds instances of the same id.
Do I have to compare all the fields manually or is there another Java-typical solution for this?
Edit for clarification:
Just updating the Set with the new instance would not be enough because there is code triggered on an update. So what I want to do is:
if (set.contains(newCat)) {
Cat current = set.get(newCat);
if (!current.equals(newCat)) { //obviously this is not enough
set.add(current);
//notify EventBusses and such
}
}
Solutions that came into my mind are:
current.requiresUpdate(newCat) //basically copy of equals() with properties
current.updateWith(newCat) //same as above but keeping the old instance
if (!current.name.euqals(newCat.name)) //for each property
only get the objects from the service that have changed. Optimal, but out of scope for me.
All of which would require somewhat redundant code which is why I was hoping there is a pattern or collection that does the work for me.
The solution can include Guava classes.
I think you have two distinct problems:
Comparing Cat objects: If two Cat objects are equal only if id, name and iq are equal, than implement the equals method accordingly.
Maintaining a collection of Cat objects: To maintain a collection of Cat objects in which there are no two objects with the same id, use a Map<Integer, Cat> as already suggested.
Your code may then look something like:
if (mapOfCats.contains(newCat.id)) {
Cat current = mapOfCats.get(newCat.id);
if (!current.equals(newCat)) {
mapOfCats.put(newCat.id, newCat);
// notify EventBusses and such
}
}
You just need to insert the value again.
If id will be match from previous cat object, it will be overwritten in set.
A HashSet internally maintains a HashMap to identify duplicates.
The simpler solution is: if found equal - remove it and add again, with updated values. The code can be somewhat like this :
yourSet.remove(cat);
yourSet.add(newCatObejectWithSameID);
newCatObejectWithSameID will have different name and iq.
Your requirements sound slightly strange - if the ID field is supposed to uniquely identify a Cat, then there should surely only ever be a single instance of a Cat with that ID. Or, at least, the corresponding fields on the multiple Cat instances should be equal.
However, assuming there can be multiple logically different Cat instances with the same ID, the easiest way to handle this is to use a Map<Integer, Cat>:
Map<Integer, Cat> cats = new HashMap<>();
for (Cat cat : getAllCats()) {
if (!cats.containsKey(cat.id)) {
cats.put(cat.id, cat);
} else {
// Do whatever - ignore, log a message, throw an exception?
}
}
Collection<Cat> catsWithUniqueIds = cats.values();
I want to write a method in java that will select certain words based on an input.
For example, if the choices were a dog, cat, lizard, eagle
and someone types in wings, it'll check to see if the choices have that attribute.
I don't know how complex this is but we've learned for loops, return, if, else and scanners so far.
You can probably maintain a list of attributes for each object, then check if the user typed attribute is part of the list for all object types you have in hand.
I suggest you look at the ArrayList JavaDoc, you will need to use it to maintain the list of attributes. If you don't feel at ease with using an ArrayList object to hold onto your attributes, you may want to use a String array instead, which will work fine too. You will also need to defined a class hierarchy and define a method that will be available in all subclasses (here's a tutorial on inheritance).
Edit
I posted this first answer before reading the comments.
If your only assignment is to provide a list of components that freeze at the user specified temperature, then a list of attributes isn't necessary. You can define a super class (lets say Element) that will define an abstract method public int getFreezingTemperature (). Then, in all subclasses, you will have to implement this method. As an example, if you create a class Water:
public class Water extends Element {
#Override
public int getFreezingTemperature () {
return 0;
}
}
And repeat the same for every element you have to create. Once you are done, whenever a user inputs a temperature, you can query your elements via the method getFreezingTemperature (), and whenever the returned temperature is above the user specified temperature, add it to a list of elements that freeze at the specified temperature.
I'm attempting to answer the substance-temperature question you mentioned in your comment. You could make an arrays as such:
String[] substances = new String[number of substances given];
Then place the substances into the array in the same order that they are given in the assignment. You can then check the user's input and determine at which index the name of the substance corresponding with their input is. For example:
//code to initialize array of substances goes here, call it "substArray"
//code to make scanner goes here, call it "scan"
int temp = scan.nextInt();
if(temp == -100)
{
System.out.println(substArray[index of substance corresponding with -100]);
}
else if...
...
This seems to be a very messy and a not very elegant program to write without use of separate classes, but hopefully this is within the range of your current knowledge and understanding.
I hope this helps,
Tyler
Edit: after reading your comments, it looks like you're going to want to do something like this.
//create your scanner, using whatever resource you are told to use
int temp=scanner.readInt()
//read in the given temperatures
if(substance1freezingpoint > temp){
System.out.println("substances 1 will freeze at " + temp);
}
if(substance2freezingpoint > temp){
System.out.println("substance 2 will freeze at " + temp);
}
....
A couple of things to note about that implementation.
It assumes that more than one substance can freeze at temp. If that isn't the case, you're going to want to use else ifs. As a question to test your learning: why is that?
It doesn't store which substances will freeze at a certain temperature, it just prints them out to the screen. How would you modify this to store the substances which meet the criteria
It doesn't deal with boiling points, but it's a pretty easy modification to make it do that.
So, does that code at least get you off on the right foot, or does it not satisfy what the problem is asking?
I have a function that returns a list like this:-
List <Column <String1, String2>>
Next I want to pass this list to a 2nd function, but
2nd function just needs a list which contains only 1st part (string1) of the Column(s) of the above list.
So I want pass just this list to 2nd function:-
List <String1>
my use case: Both the functions are from a library that I use to access database(Cassandra) for a web application. 1st function gives me a list of all columns which has two parts name(String1) and value(String2). So 1st function gives me a list of all columns(each of which has two strings) then I just need to use the list of column names to supply it to 2nd function that'll query the DB for those columns.
Since I need to do this job atleast 2-3 times before asking for data from DB for a single page, I need a superfast and a reasonably efficient method to do so.
It depends on what you mean by "efficient" (memory, execution time, something else?) and what that second function is doing.
If you care about speed and the second function is going to be looking at the items in the list repeatedly, then you should probably just copy the strings into a new List<String>:
List<String> strings = new ArrayList<String>(input.size());
for (Column<String, String> column : input) {
strings.add(column.name());
}
return strings;
If, on the other hand, the second function is going to only look at a small subset of the items or if you care more about memory than speed then you probably want a lazy view that converts items as they are accessed. Lists.transform from Google Guava can do this for you:
return Lists.transform(input, new Function<Column<String, String>, String>() {
public String apply(Column<String, String> column) {
return column.name();
}
};
Note that you may want to create he Function as a separate static class unless you're ok with it holding onto a reference to your enclosing instance. I used an anonymous class here for brevity/clarity.
I believe there is no simpler way than simply walking over the first list and ask each Column for its String1 and then add that value to your List<String1>.
If you want to separate the walking and the adding, then consider writing an Iterator which returns all the String1's from the first list, and then use traverse that.
In Scala, you could just do:
stringsList = columnsList.map(_.string2)