Direct is a class that contains 2 get methods and one of them is getName().
In the following code, I am using an array and it works correctly.
But if I want to store it in a LinkedList instead of an array, how do I iterate and reach the getName() method. I am able to iterate fine if is just a list of common primitives such as Strings but in this case where it is a list of class, I am confused on how to reach the getName() method. Thanks for helping.
private LinkedList<Direct> directList= new LinkedList();
private ListIterator<Direct> iterator = directList.listIterator();
private Direct[] direct = new Direct[100];
private int find(String name){
for (int x=0; x < direct.length; x++){
if (direct[x] != null)
if (direct[x].getName().equals(name)){
return x;
}
}
return -1;
}
Simply use directList.get(i). But you shouldn't use the index based get() method with LinkedList as it's very slow. Instead, you should use an iterator (or a for each loop, which is essentially the same):
int cnt = 0;
List<Direct> list = new LinkedList<>();
for (Direct d : list) {
if (name.equals(d.getName())) {
return cnt;
}
cnt++;
}
With an iterator:
for (Iterator<Direct> it = list.iterator(); it.hasNext();) {
Direct d = it.next();
if(name.equals(d.getName())){
System.out.println("matches");
}
}
In Java 8 you can also use the following solution (which will be slower, as it filters the entire list):
Direct d = list.stream().filter(direct -> direct.getName().equals(name)).findFirst();
There are (at least) two ways:
// generally easier to read if you don't need access to the iteration number.
for( Direct d : directList )
{
d.getName();
// ...
}
or use List#get(int) method (Although this is valid, since you are using a LinkedList this solution is O(n^2) instead of O(n) it shouldn't be used.)
for( int i = 0; i < directList.size(); ++i )
{
directList.get(i).getName();
}
Related
I have a list of custom objects. I need to get/remove a specific object from that list but the equals implemented would not work based on what I need to search.
The following would work:
int index = -1;
for(int i = 0; i < list.size(); i++) {
if(list.get(i).getAttr().equals(arg)) {
index = i;
break;
}
}
CustomObject = list.remove(index);
// use CustomObject here
I was wondering if I could do the list.remove inside the for loop despite not using an iterator since the loop breaks immediately
Using the delete(int) method in your loop will work just fine.
Your loop is closed so you have full control on i and you can use the list as you please. You don't use i after having deleted the first element that matches, so there are no caveat. If you were to reuse it, you would have to not increment it.
To avoid any trouble, the following if both more readable and expressive. Also, it's totally implementation-agnostic.
CustomObject deletedObject = null;
for (Iterator<CustomObject> i = list.iterator(); i.hasNext(); ) {
CustomObject candidate = i.next();
if (candidate.getAttr().equals(arg)) {
deletedObject = candidate;
i.remove();
break;
}
}
if (deletedObject != null) {
// Do something with deletedObject
}
There is no special program state associated with “being inside a for loop”. What matters, are the actions your program performs.
So
int index = -1;
for(int i = 0; i < list.size(); i++) {
if(list.get(i).getAttr().equals(arg)) {
index = i;
break;
}
}
CustomObject o = list.remove(index);
// use CustomObject here
is identical to
for(int i = 0; i < list.size(); i++) {
if(list.get(i).getAttr().equals(arg)) {
CustomObject o = list.remove(i);
// use CustomObject here
break;
}
}
as it performs the same actions (letting aside that the first variant will throw when no match has been found). The differences regarding local variables defined in these code snippets are, well, local and do not affect anything outside the containing method.
That said, the rule that you must not modify a collection (except through the iterator) while iterating over it, applies to iterator-based loops, where you are not in control of the iterator’s internal state. When you are using an index based loop and fully understand the implications of removing an object at a particular index (of a random access list), you can even continue iterating. The important aspects, to do it correctly, are that the indices of all subsequent elements decrease by one when removing an element, further the size decreases so you must either, reread the size or decrement a previously cached size value.
E.g., the following loop is valid
for(int i = 0; i < list.size(); i++) {// rereads size on each iteration
if(list.get(i).getAttr().equals(arg)) {
CustomObject o = list.remove(i--); // decrease index after removal
// use CustomObject here
// continue
}
}
But, of course, it’s more idiomatic to use an Iterator or removeIf, as these approaches are not only easier to handle, they also work with other collections than random access lists. And especially removeIf may be more efficient when you remove more than one element.
Just another way using streams,
List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("D");
str1.add("D");
Optional<Object> foundVal = str1.stream().filter(s ->
s.contains("D")).findFirst().map(val -> {
str1.remove(val);
return val;
});
System.out.println(str1);
System.out.print(" " + foundVal.get());
Output
[A, B, D] D
I don't understand why this is happening. I was doing a bit of research on other questions and I found out that you can't modify an collection while using a for loop. However, I am using an Iterator, why is it not working?
int counter = 0;
int otherCounter = 0;
ArrayList<Character> chars = new ArrayList<Character>();
Iterator<Character> i = chars.iterator();
for (char s : e.getMessage().toCharArray()) {
chars.add(s);
}
while (i.hasNext()) {
char s = i.next();
if (chars.get(otherCounter + 1) == s) {
counter++;
} else {
counter = 0;
}
if (counter >= 2) {
i.remove();
}
otherCounter++;
}
I am getting an error on this line for some reason:
char s = i.next();
You're adding to the collection after creating the iterator.
This throws that exception.
You need to create the iterator after you finish modifying the collection.
This is because an "enhanced for loop" as you are using it creates an Iterator behind the scenes.
In fact, when you write:
for (X x: whatever) {
// do something with x
}
the "real", generated code goes something like:
Iterator<X> iterator = whatever.iterator();
while (iterator.hasNext()) {
X x = iterator.next();
// do something with x
}
And this is true if whatever implements Iterable<X> (which List does; in fact, any Collection does)
In your example, you create a List<Character>, create a first Iterator<Character> over it, and your for loop creates another Iterator<Character>, over the same list.
Note that you created the first before you modified your List... Hence the result. The first Iterator, which you reuse only afterwards, will detect that in the meanwhile, its underlying list has been modified: boom.
I am trying to write the equivalent method from java. MyIterator extends Iterator.
public T remove(int index) {
MyIterator<T> it = support.iterator();//returns iterator over my sequence implementation
int i = 0;
T e = null;
while (it.hasNext() && i < index) {
e = it.next();
i++;
}
it.remove();
return e;
}
How can I write this to c# since there is no defined method for it.remove?
C#/.Net iterators (IEnumerator<T> as returned by IEnumerable<T> ) are read-only forward only iterators and do not allow removing items from underlying collection compared to Java's iterator.remove.
Most collections support removing items by index like List<T>.RemoveAt which would be close equivalent.
Alternatively if you just want to skip item during iteration - Enumarable.Skip or Enumerable.Where can be an option:
mySequence.Where((item,id) => id != indexToSkip)
public T remove<T>(int index)
{
IEnumerator it = support.GetEnumerator();
T e = default(T);
int i = 0;
while (it.MoveNext() && i < index)
{
e = (T)it.Current;
i++;
}
// Have to remove from the original array here because iterators are read-only
support.RemoveAt(index);
return e;
}
I think that would be a literal translation, however there are much easier ways to do this depending on the type of array I'm sure.
I have a servlet which gets variables from a form and stores them in a vector.
I want to pass the whole vector to a method in another java class.
How am I supposed to do for that?
This is what I have tried:
In servlet-
private DbUpdate dbup = new DbUpdate();
int j=0;
Vector<String> v = new Vector<String>();
v.addElement("name");
v.addElement("profession");
Enumeration vEnum = v.elements();
j = dbup.insertValues(vEnum);
DbUpdate.java class
public int insertValues(Enumeration vc) {
for (int j=1; j<14; j++) {
statement.setString(j, vc.get(j));
}
i = statement.executeUpdate();
}
It says I cannot have vc.get() method here.
Any help would be highly appreciated.
Thanks in advance.
That's really strange why you are still using such kind of obsolete classes even you are using JDK 1.5+.
Use List instead.
List<String> params = Arrays.asList("name", "profession");
// if you prefer you can also create an ArrayList<String>() and add it one by one
dbUp.insertValues(params);
and in you DbUpdate.java, do something like
public int insertValues(Collection<String> params){
int i = 0;
for (String param : params){
statement.setString(++i, param);
}
return statement.executeUpdate();
}
Edit:
If in any case you really really want to use Enumeration, you need to understand Enumeration works similar to an Iterator which provide you an interface to iterate through a collection of object. Hence it should look something like:
public int insertValues(Enumeration<String> params){ // or use Enumeration<?>, but you need
// further casting below
int j = 0;
while (params.hasMoreElements()) {
String param = params.nextElement();
statement.setString(++j, param);
}
return statement.executeUpdate();
}
If you iterate all elements of enum, you can use below code
for(Enumeration e : vc.values())
Iterate over Enumeration using following two methods,
hasMoreElements()
Tests if this enumeration contains more elements.
nextElement()
Returns the next element of this enumeration if this enumeration
object has at least one more element to provide.
You need to modify your insertValues() method,
public int insertValues(Enumeration vc){
while(vc.hasMoreElements()){
if(j<14){
statement.setString(j, vc.get(j));
j++;
}
}
i = statement.executeUpdate();
return 0; // return what you want to return
}
I have a List containing HashMaps. Each HashMap in the list might have multiple key/value pairs. I want to indexOf on the list to find out the index of the element where the passed in HashMap is. However, the problem is that equals method of HashMap looks at all the entire entrySet while comparing. Which is not what I want.
Example:
List<HashMap> benefit = new ArrayList<HashMap>();
HashMap map1 = new HashMap();
map1.put("number", "1");
benefit.add(map1);
HashMap map2 = new HashMap();
map2.put("number", "2");
map2.put("somethingelse", "blahblah"); //1
benefit.add(map2);
HashMap find = new HashMap();
find.put("number", "2");
int index = benefit.indexOf(find);
if (index >= 0)
System.out.println(benefit.get(index).get("number"));
The above code does not print anything because of line with //1.
What do I have to do so that the above code actually prints 2?
Is there a way to implement comparable on the list so that I can define
my own?
I think you're looking for retainAll(), so you can compare only the elements you're interested in:
int index = myIndexOf(benefit, find);
...
static int myIndexOf(List<HashMap> benefit, Map find) {
int i = 0;
for (Map map : benefit) {
Map tmp = new HashMap(map);
tmp.keySet().retainAll(find.keySet());
if (tmp.equals(find)) {
return i;
}
i++;
}
return -1;
}
It's possible, of course, to declare your own subclass of List that overrides the indexOf method with this behaviour. However, I don't think that's a good idea. It would violate the contract of the indexOf method:
returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i)))
This would be confusing to someone else maintaining the code. You might then think that you could subclass HashMap to redefine equals, but that would violate the symmetry property of Object.equals().
The way you are trying to achieve your goal is wrong. The indexOf method works exactly as it should in this case. It is trying to find an exact match, not a partial one.
What you are trying to do, if I get it correctly, is to find a map in your list of maps that contains a specific entry. In this case, you should manually perform this search, by going through all the maps, calling containsKey (), and then comparing the value you are expecting to find with the value associated with the key.
The other way would be to create a proxy class around your List, and add a new method findMapWithEntry (String key, String value), which would perform this seach for you (the same search I described above).
Why not change the way you search?
List<Map> matchingBenefits = new ArrayList<Map>();
for (Map m : benefit) {
if (m.containsKey("number") && m.get("number").equals("2"))
matchingBenefits.add(m);
}
for (Map m : matchingBenefits) {
System.out.println(m.get("number"));
}
You can always override the indexOf method. Looking at the source for ArrayList:
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
So it's not a very complex search algorithm at all. You may look at something like:
List benefit = new ArrayList(){
public int indexOf(Object o){
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
else {
for (int i = 0; i < size; i++) //traverse the hashmaps
Object key = ((HashMap)o).keySet().get(0); //assuming one pair
Object val = ((HashMap)o).valueSet().get(0);
if (
((HashMap)elementData[i]).containsKey(key) &&
((HashMap)elementData[i]).get(key).equals(val))
return i;
}
return -1;
};
My advice would be to consider a different data structure, perhaps writing your own one for it.
Given that you cannot change the design, would writing your own find method help?
The code below should work if I understood what you're trying to do and it runs in O(n)
public static String find(List<HashMap<String,String>> listMap, String key, String value) {
for(int i = 0; i < listMap.size(); i++)
if(listMap.get(i).get(key).equals(value))
return value;
return null;
}