Is there any easy way to search through an arraylist?
i see there are many things to do with collections like removeAll() and add() is there anything like this for searching through the list
Add a method to your UserArchive class that loops through the list and compares each user id to the one passed in.
public User findById(int id) {
for (User u : list) {
if (u.getCustomerID() == id) {
return u;
}
}
return null; // or empty User
}
You have the option of do a if in your loop and look the id for each instance of User in the loop:
for (User user : list) {
if (user.getCustomerID == [The id to lookup]) {
// Whatever you want to do
}
}
Or you could override the equals() method for your User class and unlock the
List.contains function if you compare another instance of User instead of the CustomerID.
The equals' functions header say:
Returns true if this list contains the specified element. More
formally, returns true if and only if this list contains at least one
element e such that (o==null ? e==null : o.equals(e)).
This is why you got to override equals for you object. A lot of functions use equals() for object and if you care the result to be good, you have to override the function.
// Or whatever instance of User you want to compare
User custToLookup = new User(idToLookup, "", "", "");
// You could stop here if you only want to know if the instance exist in the list
if (list.contains(custToLookup)){
for (User user : list) {
if (user.equals(custToLookup) {
// Whatever you want to do
}
}
}
*Edit : Forgot some words
Related
Suppose I have something as follows where DataImporter is a utility to retrieve data from the file system and has child data importers within it for retrieving data from the sub folders based on the category string:
List<String> categories = getCategories();
boolean doesChildImporterExist = false;
for (String category : categories)
{
DataImporter childDataImporter=importer.getChild(category);
if (childDataImporter != null)
{
doesChildImporterExist = true;
populateImportedData(childDataImporter.importData());
}
}
if(!doesChildImporterExist)
populateImportedData(importer.importData());
I know the other option is to construct a List of child data importers and check for its size, if it is 0 or not and based on that import the data using the desired importer. However, I'm trying to understand what is wrong with using the boolean flag here?
Assume that the code above is within a method and using Java 1.7.
When you use a boolean flag in a method as a branch decider (not the best terminology),
you are actually taking the functionality of two different methods and smashing them into one method.
Often,
the better solution is to have a method for the shared functionality and a second method for the super set functionality.
For example:
public DataImporter doYourCategoryStuff()
{
List<String> categories = getCategories();
... blah including the for loop.
return theDataImporter;
}
public void doAllTheStuffs()
{
final DataImporter theDataImporter;
theDataImporter.doYourCategorStuff();
populateImportedData(theDataImporter.importData());
}
Edit
More to the point in your code.
In your code,
the boolean flag indicates "I did something to a child importer and need to update parent importer".
In this case you are smashing "identify things to update" and "do the update" together;
split them.
Consider something like this:
Set<DataImporter> updateSet = new HashSet<>();
for (category for loop)
{
final DataImporter child = importer.getChild(category);
if (child != null)
{
updateSet.add(child);
updateSet.add(importer);
}
}
for (final DataImporter current : updateSet)
{
current.importData();
}
Even though the add(importer) (the parent) may be called multiple times,
the set will only ever contain one instance of each DataImporter.
This should be reasonable even if you don't implement hashCode and equals on DataImporter, since the parent reference will always be the same.
I need help. Would you give me solution how to fix my code?
I have an arraylist where each contains some element. And I want to use search method to find it by just one element keyword.
This the code to add
System.out.print("ID_Cargo >> ");
ID_Cargo=scan.next();
System.out.print("No_Container >> ");
No_Container=scan.next();
CARGO.add(new CARGO(ID_Cargo,No_Container));
And this is to search
String find;
System.out.println("ID Cargo : ");
find=scan.next();
if(CARGO.contains(find)){
System.out.println("FOUND");
}
else{
System.out.println("NOT FOUND");
}
the search is always return Not found but the element what I find is exist. How to fix it in order to return FOUND?
Thank's.
It looks like your CARGO list contains CARGO objects (not a good idea to use the same name), but you are checking if a String (find) is contained in that List, which naturally returns false.
If you wish to search for a CARGO instance by its identifier, a HashMap<String,CARGO> would be more suitable.
Map<String,CARGO> cargoMap = new HashMap<>();
cargoMap.put(ID_Cargo,new CARGO(ID_Cargo,No_Container));
...
if(cargoMap.containsKey(find)){
System.out.println("FOUND");
} else {
System.out.println("NOT FOUND");
}
EDIT:
To display the properties of the CARGO isntance having the find key (assuming your CARGO class has such getter methods) :
CARGO cargo = cargoMap.get(find);
if (cargo != null) {
System.out.println("FOUND: " + cargo.getCargoID() + " " + cargo.getContainerNo());
} else {
System.out.println("NOT FOUND");
}
Your list CARGO contains not Strings but CARGO instances (you should really rename your list to avoid confusion!). Because of that fact you need to search with a CARGO instances not with a String.
CARGO.contains(find)
should be
CARGO.contains(new CARGO(find, null) // because you search for the ID the second argument is empty
You need to write an equals method in your CARGO class which only compared the ID
That should work.
But if you want to search often, you should consider a Map instead of a List.
P.s. I cannot provide concrete code, because I do not know exactly how your class looks like
your CARGO list has objects of Cargo, and you're trying to find a "String" in that list, that is why you are getting Not Found. use a loop instead:
this is a metod that takes a list and ID and return true if a cargo with that ID exist, otherwise false
public boolean isExist(ArrayLisr<Cargo> CARGO , String ID) {
for(int i = 0; i < CARGO.size(); i++){
Cargo cargo = CARGO.get(i);
if( cargo.getID.equals(ID)
return true;
}
return false;
}
the method .get(i) returns the object in the list that is in the position i, the method .size() returns the number of objects in that list
the method .getID is a method you should create in your Cargo class, and make it return the ID
Basically, this method takes the objects in the list one by one, check if that object has the ID we want or not, return true if it has it, go to the other object otherwise. if we reached the end of the list and none of the objects in that list returned true, that means no object with that ID is exist, so return false
This is how I understand method getUser below :
Return a User object or null
Get a Set of users and assign them to userSer.
If the set is not empty begin iterating over the set but
return the first user within the set.
Here is the method :
private User getUser(UserDet arg)
{
Set<User> userSet = arg.getUsers(User.class);
if (CollectionUtils.isNotEmpty(userSet))
{
for (User user : userSet)
{
return user;
}
}
return null;
}
I think I could replace the method with this :
private User getUser(UserDet arg)
{
Set<User> userSet = arg.getUsers(User.class);
if (CollectionUtils.isNotEmpty(userSet))
{
return userSet.iterator().next();
}
else {
return null;
}
}
This new method removes the loop and just returns the first element in the set, same as original implemention. Is it correct?
Yes. Actually, it's pretty much almost the same thing, as a foreach loop is syntactic sugar for using an iterator from an Iterable.
Note, however, that you don't need the nonempty check in the first variant, since the loop won't iterate in the case of an empty set anyway.
yes both are same. in first implementation, control will return on first iteration of the loop from the function and consequently loop will end.
Yes it is correct, I'd even go for removing the CollectionUtils.isNotEmptySet and use the Iterator's hasNext method... If the set is guaranteed to be non-null.
It seems to be correct, but it will only make the method a bit easier to read, it will not optimize it in terms of performance. Still I think the change is good and you should do it.
Yes, it does pretty much the same, but if your spec says to start iterating then maybe you should - maybe this method will be extended in the future.
BTW: it is a good convention that your method has only one return statement (i.e. you can create a variable, which will be returned, assigned a null at the beginning and assign a user inside your loop)
Yes. Both the methods return the first element in the set. The first method seems to have been written for something else previously and changed then keeping the for loop intact.
In anycase, the second method that you're proposing won't give any significant performance benefit but should be a better way than the first one.
So in case, UserDet#getUsers(Class) never returns null (but an empty Set in case no user could be found), the shortest (and in my opinion most readable) form is:
private User getUser(UserDet arg) {
Set<User> userSet = arg.getUsers(User.class);
return userSet.isEmpty() ? null : userSet.iterator().next();
}
I would do this.
I won't run a loop and more over I'l add a null check.
private User getUser(UserDet arg) {
Set<User> userSet = arg.getUsers(User.class);
if (userSet != null && userSet.size() > 0) {
return userSet.iterator().next();
}
return null;
}
I am using JSF2.0 in my application.
The business requirement in my project is such that when page loads a list is displayed. The list is coming from DAO layer or web service layer. Lets call this original List.
Now we have 2 lists, copies of each other in which is just the original list and the other is bounded to the JSF
Now the list is editable list so I am using a to display the list and each cell in the is a .
Now on click of SAVE button the modified list by the user (since the list is editable) is compared with the original list.
Only if the 2 lists are different then the modified list is sent back to webservice.
The problem and issue that I am facing is that in the first line of save() method itself both the original and modified list is exactly same and point only to the modified list.
So I am unable to compare the 2 lists.
My implementation is as below-
PhaseListener is calling below method on page load
public String populateDataTable() {
this.orderList = new ArrayList<ItemOrder>();
this.originalOrderList = new ArrayList<ItemOrder>();
MockWebService mockService = new MockWebService();
this.setOrderList(mockService.mockWSMethod());
this.originalOrderList = this.getOrderList();//i know this is where i am doing something wrong. i need to deep copy a list. but for this i cannot make an additional web service call and call that web service again and store the list in originalOrderList
return "view";
}
On click of save button
public String saveAction() {
boolean isSame = true; // true if same and false if different
for (int i = 0; i < this.originalOrderList.size(); i++) {
if (!this.originalOrderList.get(i).equals(this.orderList.get(i))) {
isSame = false;
}
}
//however both originalOrderList and orderList have the same modified List.
if (isSame == true) {
System.out.println("Same lists");
} else {
System.out.println("Different lists");
}
return "default";
}
Please do help me.
Thanks in advance,
Kiran
As you mentioned the problem you are facing is originalOrderList is a shallow copy of orderList (assuming getOrderList() is returning an orderList reference). In your case both orderList and originalOrderList are references pointing to the same ArrayList object and if a change is made to the value of your orderList, then the originalOrderList reflects that change because it shares the same reference.
The solution is to do a deep copy of your originalOrderList :
this.originalOrderList = this.getOrderList().clone();
if your ItemOrder is an immutable object otherwise :
public static List<ItemOrder> cloneList(List<ItemOrder> list) {
List<ItemOrder> clone = new ArrayList<ItemOrder>(list.size());
for(ItemOrderitem: list) clone.add(item.clone());
return clone;
}
and you will have to get your ItemOrder object to implement the Cloneable interface, and implement the clone() method.
I'm looking for a Google Collections method that returns the first result of a sequence of Suppliers that doesn't return null.
I was looking at using Iterables.find() but in my Predicate I would have to call my supplier to compare the result against null, and then have to call it again once the find method returned the supplier.
Given your comment to Calm Storm's answer (the desire not to call Supplier.get() twice), then what about:
private static final Function<Supplier<X>, X> SUPPLY = new Function<....>() {
public X apply(Supplier<X> in) {
// If you will never have a null Supplier, you can skip the test;
// otherwise, null Supplier will be treated same as one that returns null
// from get(), i.e. skipped
return (in == null) ? null : in.get();
}
}
then
Iterable<Supplier<X>> suppliers = ... wherever this comes from ...
Iterable<X> supplied = Iterables.transform(suppliers, SUPPLY);
X first = Iterables.find(supplied, Predicates.notNull());
note that the Iterable that comes out of Iterables.transform() is lazily-evaluated, therefore as Iterables.find() loops over it, you only evaluate as far as the first non-null-returning one, and that only once.
You asked for how to do this using Google Collections, but here's how you would do it without using Google Collections. Compare it to Cowan's answer (which is a good answer) -- which is easier to understand?
private static Thing findThing(List<Supplier<Thing>> thingSuppliers) {
for (Supplier<Thing> supplier : thingSuppliers) {
Thing thing = supplier.get();
if (thing != null) {
return thing;
}
}
// throw exception or return null
}
In place of the comment -- if this was the fault of the caller of your class, throw IllegalArgumentException or IllegalStateException as appropriate; if this shouldn't have ever happened, use AssertionError; if it's a normal occurrence your code that invokes this expects to have to check for, you might return null.
What is wrong with this?
List<Supplier> supplierList = //somehow get the list
Supplier s = Iterables.find(supplierList, new Predicate<Supplier>(){
boolean apply(Supplier supplier) {
return supplier.isSomeMethodCall() == null;
}
boolean equals(Object o) {
return false;
}
});
Are you trying to save some lines? The only optimisation I can think is to static import the find so you can get rid of "Iterables". Also the predicate is an anonymous inner class, if you need it in more than one place you can create a class and it would look as,
List<Supplier> supplierList = //somehow get the list
Supplier s = find(supplierList, new SupplierPredicateFinder());
Where SupplierPredicateFinder is another class.
UPDATE : In that case find is the wrong method. You actually need a custom function like this which can return two values. If you are using commons-collections then you can use a DefaultMapEntry or you can simply return an Object[2] or a Map.Entry.
public static DefaultMapEntry getSupplier(List<Supplier> list) {
for(Supplier s : list) {
Object heavyObject = s.invokeCostlyMethod();
if(heavyObject != null) {
return new DefaultMapEntry(s, heavyObject);
}
}
}
Replace the DefaultMapEntry with a List of size 2 or a hashmap of size 1 or an array of length 2 :)