Consider i have a List Of Objects, and i convert it to a Set to make some actions like this :
List<User> listUser = new ArrayList<>();
listUser.add(new User(1, "user1"));
listUser.add(new User(2, "user2"));
listUser.add(new User(3, "user3"));
Set<User> myset = new HashSet<>(listUser);
I know there are a contains(Object o) but i want to check with the attributes of my Object.
My Question is What is the best way to check if the Set contain an Object with ID = 1 or user = "user1" or any attribute
Thank you.
Does your User class override equalsusing just the ID? If so, you could use:
if (mySet.contains(new User(1, "irrelevant"));
Note that it's quite odd to have something called mySet which is actually a List rather than a Set... I'd consider either changing the name or the type. If you use HashSet you'll need to override hashCode as well as equals, but you should do that anyway to obey the normal contracts from Object.
If you want to be able to check by multiple different attributes - or if you don't want to override equality in User - then you could consider creating maps instead, e.g.
Map<Integer, User> usersById = new HashMap<>();
Map<String, User> usersByName = new HashMap<>();
...
Then you need to keep all the maps in sync, of course - and you need to consider what happens if you've got multiple users with the same name, etc.
You are correct that you cannot use Java streams with Java 7 (they were introduced in Java 8). For Java 7 I would suggest an enhanced for loop in which you check your search condition (if (u.getId() == 1)) and act appropriately.
If you are ever getting a problem with the linear search that the for loop would do, you may build maps: HashMap<Integer, User> for allowing lookup by ID and HashMap<String, User> for lookup by user name. Map.containsKey() will tell you whether the map contains a specific user. You will need to take care that the maps contain all your users, and also that users are removed from the maps when deleted from your set/list, of course (oops, only saw now that Jon Skeet has already said all of this, sorry).
For anyone using Java 8 and reading along here, use of streams needs not be very fancy. A couple of examples:
boolean containsUser1 = myset.stream().anyMatch(u -> u.getId() == 1);
This yieds true.
User[] u1Array = myset.stream().filter(u -> u.getId() == 1).toArray(User[]::new);
Set<User> u1Set = myset.stream().filter(u -> u.getUserName().equals("user1")).collect(Collectors.toSet());
Each of these two yield [1 user1] (the first one as an array, the second as s Set, obviously). Each use of a stream does a linear search behind the scenes.
That said, you can do fancy things with streams. I’ve found it a pleasure learning them and using them, look forward to that.
Simpliest and fanciest way i think is to override equals method in your User class by just considering the id.
Then you can use the contains method from the List interface
Related
I'm doing a personal project.
After a lot of maps, I came to the point where I want to enter a map inside another map... Let me explain better.
I have this Map atPropostas which have information about a person, but at some time of the program, I want to add to that person a boss email.
private Map<String, Long> atPropostas;
private Map<String,Map<String,Long>> atOrientadores;
To add that boss email, I've done this:
for (Map.Entry<String, Long> atprop : atPropostas.entrySet()) {
for (Map.Entry<String, Proposta> prop : propostas.entrySet()) {
if (prop.getValue().getTipo().equals("T2") && propostas.containsKey(atprop.getKey())) {
atOrientadores.put(prop.getValue().getEmailDocente(), atprop);
}
}
}
But, atprop value, inside atOrientadores.put() it produces an error:
java: incompatible types:
java.util.Map.Entry<java.lang.String,java.lang.Long> cannot be
converted to java.util.Map<java.lang.String,java.lang.Long>
I have tried to cast the atprop:
atOrientadores.put(prop.getValue().getEmailDocente(), (Map<String, Long>) atprop);
And the compiler error disappears, but the App itself, doesn't working.
You can't convert Map.Entry in to a Map with casting.
Map and entry represent inherently different notions. Map consists of entries, it isn't an entry.
You can create a single entry map by using static method Map.ofEntries() available with Java 9
atOrientadores.put(prop.getValue().getEmailDocente(), Map.ofEntries(atprop));
Sidenote: it's highly advisable to use English while giving names to variables, classes, etc. in your application. It makes it easier to reason about your code.
I don't know for sure what atprop is meant to represent, but you've mentioned a person and an email. I advise you to consider creating classes that would correspond to a person and an email instead of complicating your code and dealing with nested maps.
I have some data points collected from different companies identified by companyId, and the name property of each data point could be duplicate in one company or among different companies.The problem is to group all the data points by its name property which belong to different companies, which means we ignore the data point if its company has already existed in the group.
For example the data points are:
companyId data-point name
1---------------------A
1---------------------A
1---------------------B
2---------------------A
3---------------------B
The results would be:
data-point name group
A=================(1,A)(2,A)
B=================(1,B)(2,B)
We can see that the second data point A from company 1 was ignored.
There are two ways as far as i know to do deduplicate work.
1.Build a Map<String(data point name), Set<Long(companyId)>>
Map<String, Set<Long>> dedup = new HashMap<>();
for(DataPoint dp : datapoints){
String key = dp.getName();
if(!dedup.contains(key)){
dedup.put(key, new HashSet<Long>());
}
if(dedup.get(key).contains(dp.getCompanyId()){
continue;
}
dedup.get(key).add(dp.getCompanyId());
}
2.Build a Big Set<String>
Set<String> dedup;
for(DataPoint dp : datapoints){
String key = dp.getName() + dp.getCompanyId();
if(dedup.contains(key)){
continue;
}
dedup.add(key);
}
So which one is better or more appropriate ?
Method (1) is way better, because method 2 kind of destroys the type information.
There are ready-made collections already available for such cases if you want a well-tested robust implementation, with many additional features.
Guava: https://google.github.io/guava/releases/21.0/api/docs/com/google/common/collect/HashMultimap.html
Eclipse collections:
https://www.eclipse.org/collections/
If you just want a simple implementation, you can follow your method (1) and do it yourself.
Result would be something like this:
{
"A": [1, 2],
"B": [1, 2]
}
Few reasons why I don't prefer method 2:
The method is not reliable. If company name ends with a number, then you might have false deduplication. So, you may need to add a special character like so: <id>~<name>
If you need to consider one more parameter later, it becomes more messy. You may have to do <id>~<name>~<pincode> etc.,
In method 1, you have the added convenience that you can put the company bean directly, if you implement a hashcode and equals which are based on the companyId field alone
The easiest way to do (1) would be:
Map<String, Set<Long>> dedup =
datapoints.stream().collect(
groupingBy(
DataPoint::getName,
mapping(DataPoint::getCompanyId, toSet()));
The easiest way to do (2) would be:
Set<String> dedup =
datapoints.stream()
.map(d -> d.getName() + d.getCompanyId())
.collect(toSet());
The one you choose depends upon what you're trying to do, since they yield different types of data, as well as potentially different results.
I've got loads of the following to implement.
validateParameter(field_name, field_type, field_validationMessage, visibleBoolean);
Instead of having 50-60 of these in a row, is there some form of nested hashmap/4d array I can use to build it up and loop through them?
Whats the best approach for doing something like that?
Thanks!
EDIT: Was 4 items.
What you could do is create a new Class that holds three values. (The type, the boolean, and name, or the fourth value (you didn't list it)). Then, when creating the HashMap, all you have to do is call the method to get your three values. It may seem like more work, but all you would have to do is create a simple loop to go through all of the values you need. Since I don't know exactly what it is that you're trying to do, all I can do is provide an example of what I'm trying to do. Hope it applies to your problem.
Anyways, creating the Class to hold the three(or four) values you need.
For example,
Class Fields{
String field_name;
Integer field_type;
Boolean validationMessageVisible;
Fields(String name, Integer type, Boolean mv) {
// this.field_name = name;
this.field_type = type;
this.validationMessageVisible = mv;
}
Then put them in a HashMap somewhat like this:
HashMap map = new HashMap<String, Triple>();
map.put(LOCAL STRING FOR NAME OF FIELD, new Field(new Integer(YOUR INTEGER),new Boolean(YOUR BOOLEAN)));
NOTE: This is only going to work as long as these three or four values can all be stored together. For example if you need all of the values to be stored separately for whatever reason it may be, then this won't work. Only if they can be grouped together without it affecting the function of the program, that this will work.
This was a quick brainstorm. Not sure if it will work, but think along these lines and I believe it should work out for you.
You may have to make a few edits, but this should get you in the right direction
P.S. Sorry for it being so wordy, just tried to get as many details out as possible.
The other answer is close but you don't need a key in this case.
Just define a class to contain your three fields. Create a List or array of that class. Loop over the list or array calling the method for each combination.
The approach I'd use is to create a POJO (or some POJOs) to store the values as attributes and validate attribute by attribute.
Since many times you're going to have the same validation per attribute type (e.g. dates and numbers can be validated by range, strings can be validated to ensure they´re not null or empty, etc), you could just iterate on these attributes using reflection (or even better, using annotations).
If you need to validate on the POJO level, you can still reuse these attribute-level validators via composition, while you add more specific validations are you´re going up in the abstraction level (going up means basic attributes -> pojos -> pojos that contain other pojos -> etc).
Passing several basic types as parameters of the same method is not good because the parameters themselves don't tell much and you can easily exchange two parameters of the same type by accident in the method call.
i am going to type my code here and then I will explain my problem below.
for (int i = 0; i < sales.totalSales(); i++) {
EntidadGeo gec = sales.getSale(i).getCustomer();
EntidadGeo get = sales.getSale(i).getStore();
int[] c = geo.georeferenciar(sales.getSale(i).getCustomer().getCP(), ventas.getVenta(i).getCCustomer().getCalle(), ventas.getVenta(i).getCCustomer().getProvincia());
gec.setX(c[0]);
gec.setY(c[1]);
int[] c2 = geo.georeferenciar(ventas.getSale(i).getStore().getCP(), ventas.getVenta(i).getStore().getCalle(), ventas.getSale(i).getStore().getProvincia());
get.setX(c2[0]);
get.setY(c2[1]);
mapaventas.representar(gec, get);
}
I have that for loop, what i want to do in my project is to print in a map. The point is what I need to draw in the map are customers and stores and one store can sell to many customers at the same time. In my project I am using MVC pattern, this part belongs to Controller part, and in the model part i draw the map.
It works now but the problem is that my project draw one customer and one store instead of 4 customers per 1 store.
Thanks
Your problem is here:
mapaventas.representar(gec, get);
So it looks like you have a Map<Vendor, Client> which will only associate only one client per vendor. I have to guess at this because we have no knowledge what the method above does. If I am correct a better solution perhaps is to use a Map<Vendor, ArrayList<Client>>. so that a Vendor can be associated with multiple clients. Then you would do something like
ArrayList<Client> getList = mapaventas.get(gec);
// if the above is null, create the arraylist first and put it
// and the gec into the map.
getList.add(get);
Note that my variable names and types will not be the same as yours, but hopefully you will understand the concept I'm trying to get across. If not, please ask.
It sounds like your database has a one-to-many relation between Store and Customer. A corresponding object model might be List<Map<Store, List<Customer>>>. Because a Customer may trade at more than one Store, you want "to check there if there is an IdStore already drawn, and then I don't want to draw it."
One approach would be to iterate through the List and add entries to a Set<Location>. Because implementations of Set reject duplicate elements, only one copy would be present, and no explicit check would be required. As a concrete example using JMapViewer, you would add a MapMarker to the mapViewer for each Location in the Set, as shown here.
I need to store values specific to a username into memory, I was thinking about something like dynamically naming vars, so that I could do something like
["bubby4j_falling"] = true;
and index it by
["bubby4j_falling"]
But, this is just a example, I know that won't work, I just want a way to quickly and simply get and store things dynamically.
You want to use a Map with string keys, for example a HashMap<String, something>.
Your example would look like this:
Map<String, Boolean> map = new HashMap<String, Boolean>();
map.put("bubby4j_falling", true);
if(map.get("bubby4j_falling")) {
...
}
Actually, in your case a Set<String> would be more useful:
Set<String> fallingUsers = new HashSet<String>();
fallingUsers.add("bubby4j");
if(fallingUsers.contains("bubby4j")) { ... }
But uf you already have User objects (and you should), you should better use a Set<User>, or even let this falling simply be a property of the user object. Then you could have a Map<String, User> to get the user objects by name.
#Paŭlo Ebermann's answer is spot on.
I just want to point out that the Java language has nothing that resembles a dynamic variable. All Java variable names and their types are declared in the Java source code. Not even reflection will allow you to create new variables on the fly in an existing class.
Java is designed as a static programming language, and it works best if you use it that way.
(In theory, if you mess around with source code or byte code generation technologies, you can dynamically create a new class with new variables. However, this involves a HUGE amount of work, and not something that a sensible programmer contemplate doing to solve a simple problem. Besides, I doubt that this approach would actually help in your particular case.)