I am iterating on the elements of a list of String objects
one after the other:
LinkedList list;
// add values to the list here
for (int i = 0; i < list.size(); i++)
System.out.println(list.get(i));
Here, each and every time i invoke get() on list, the list is iterated from one of its ends all the way to the i-th element-- so the complexity of the above loop is O(n^2).
Is is a.) the same as above for enhanced-for loop, or b.) is for-loop maintaining the pointer where it's last have been and thus the complexity of the below loop is O(n)?
for (String s:list)
System.out.println(s);
If case (b) above -- which i think it is -- is there any advantage of using an iterator on the list. this is plain iteration-- there's no going back&forth. EDIT: ..and my list operation is read-only.
TIA.
The "enhanced for loop" as you call it (it's actually called the foreach loop) internally uses an iterator for any iterable - including linked lists.
In other words it is O(n)
It does handle looping over arrays by using an integer and iterating over it that way but that's fine as it performs well in an array.
The only advantages of using an iterator manually are if you need to remove some or all of the elements as you iterate.
A foreach loop like this:
for (String s:list)
System.out.println(s);
Would be desugared to something like
for(Iterator<String> iter = list.iterator(); iter.hasNext();) {
String s = iter.next();
System.out.println(s);
}
i.e. it is equivalent to using an Iterator. And much better than using a standard for loop.
Enhanced loop uses an Iterator behind the scenes [1] if it is about lists.
In your case you have a linked list (which keeps pointers to next-previous items), so by using an enhanced for (iterator) you have sequential read complexity O(1).
If you use the for you suggested, you're accessing your list randomly, which is O(n) for the LinkedList but it would be O(1) if it was an ArrayList.
So it can be enhanced if used in a List with sequential read complexity < random read complexity
[1] why is enhanced for loop efficient than normal for loop
Enhanced for loop is useful in certain situations like when there is a need to search a key in an array,where it obtains one element at a time in sequence. It eliminates the need to establish loop counter,specify starting and ending value.So based on the requirement simple for loop or enhanced for loop can be used.
Related
i have to arrays: arrA and arrB. arrA and arrB are Lists of objectss of diffrent types and add function converts objects A to objects B. I want to add each object from arrA to arrB and remove that object from arrA. Im trying to do this by stream:
arrA.stream().foreach(c -> {arrB.add(c); arrA.remove(c);});
when i execute this, two things are happening:
not all objects are passed from arrA to arrB.
after few iterations null pointer exception is thrown.
i gues it's because length of array is decreased after each remove() call and the counter of iterations is increased (only objects under odd indexes are passed to arrB)
Now i could solve this by copying array in one stream call and then remove objects in second stream call but this doesnt seem correct for me.
What would be proper solution to this problem?
EDIT.
Additional information:
in real implementation this list if previously filtered
arrA.stream().filter(some condition).foreach(c -> {arrB.add(c); arrA.remove(c);});
and its called few times to add elements meeting diffrent conditions to diffrent lists (arrC, arrD etc.) but each object can be only on one list
Streams are designed to be used in a more functional way, preferably treating your collections as immutable.
The non-streams way would be:
arrB.addAll(arrA);
arrA.clear();
However you might be using Streams so you can filter the input so it's more like:
arrB.addAll(arrA.stream().filter(x -> whatever).toList())
then remove from arrA (thanks to #Holgar for the comment).
arrA.removeIf(x -> whatever)
If your predicate is expensive, then you could partition:
Map<Boolean, XXX> lists = arrA.stream()
.collect(Collectors.partitioningBy(x -> whatever));
arrA = lists.get(false);
arrB = lists.get(true);
or make a list of the changes:
List<XXX> toMove = arrA.stream().filter(x->whatever).toList();
arrA.removeAll(toMove);
arrB.addAll(toMove);
As the others have mentioned, this is not possible with foreach - as it is impossible with the for (A a: arrA) loop to remove elements.
In my opinion, the cleanest solution is to use a plain for while with iterators - iterators allow you to remove elements while iterating (as long as the collection supports that).
Iterator<A> it = arrA.iterator()
while (it.hasNext()) {
A a = it.next();
if (!check(a))
continue;
arrB.add(a);
it.remove();
}
This also saves you from copying/cloning arrA.
I don't think you can remove from arrA while you iterate over it.
You can get around this by wrapping it in a new ArrayList<>();
new ArrayList<>(arrA).stream().foreach(c -> {arrB.add(c); arrA.remove(c);});
i guess it's because length of array is decreased after each remove() call and the counter of iterations is increased
Right. the for-each-loop is just like a normal for-loop, but easier to write and read. You can think of it as syntactic sugar. Internally it will either use an Iterator or array indices. The forEach method of streams is a more fancy version of it that allows parallel execution and functional coding style, but has its own drawbacks.
As with any indexed loop, removing an element while looping breaks the loop. Consider having three elements with indices 0, 1, and 2. When you remove element 0 in the first iteration, the list items will shift one up and the next iteration you'll have elements 0 (previously 1) and 1 (previously 2). Your loop variable now points to 1, so it skips the actually next item. When it gets to index 2 the loop you're working on only has one item left (you removed two), which throws an error because the index is out of bounds.
Possible solutions:
Use the List methods for cloning and clearing lists.
Do it with two loops if you really need to call the methods on each single item.
You could just do Collections.addAll. Then when that's finished. just call clear() on arrA.
Problem
I'm writing a simple Java program in which I have a TreeSet which contains Comparable elements (it's a class that I've written myself). In a specific moment I need to take only the first k elements from it.
What I've done
Currently I've found two different solution for my problem:
Using a simple method written by me; It copies the first k elements from the initial TreeSet;
Use Google Guava greatestOf method.
For the second option you need to call the method in this way:
Ordering.natural().greatestOf(mySet, 80))
But I think that it's useless to use this kind of invocation because the elements are already sorted. Am I wrong?
Question
I want to ask here which is a correct and, at the same time, efficient method to obtain a Collection derived class which contains the first k elements of a TreeSet?
Additional information
Java version: >= 7
You could use Guava's Iterables#limit:
ImmutableList.copyOf(Iterables.limit(yourSet, 7))
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Iterables.html#limit(java.lang.Iterable, int)
I would suggest you to use a TreeSet<YourComparableClass> collection, it seems to be the solution you are looking for.
A TreeSet can return you an iterator, and you can simply iterates K times, by storing the objects the iterator returns you: the elements will be returned you in order.
Moreover a TreeSet keep your elements always sorted: at any time, when you add or remove elements, they are inserted and removed so that the structure remains ordered.
Here a possible example:
public static ArrayList<YourComparableClass> getFirstK(TreeSet<YourComparableClass> set, int k) {
Iterator<YourComparableClass> iterator = set.iterator();
ArrayList<YourComparableClass> result = new ArrayList<>(k); //to store first K items
for (int i=0;i<k;i++) result.add(iterator.next()); //iterator returns items in order
//you should also check iterator.hasNext(); if you are not sure to have always a K<set.size()
return result;
}
The descendingIterator() method of java.util.TreeSet yields elements from greatest to least, so you can just step it however many times, inserting the elements into a collection. The running time is O(log n + k) where k is the number of elements returned, which is surely fast enough.
If you're using a HashSet, on the other hand, then the elements in fact are not sorted, so you need to use the linear-time selection method that you indicated.
well I know it is very novice question, but nothing is getting into my mind. Currently I am trying this, but it is the least efficient way for such a big number. Help me anyone.
int count = 66000000;
LinkedList<Integer> list = new LinkedList<Integer>();
for (int i=1;i<=count;i++){
list.add(i);
//System.out.println(i);
}
EDIT:
Actually I have o perform operation on whole list(queue) repeatedly (say on a condition remove some elements and add again), so having to iterate whole list became so slow what with such number it took more than 10min.
the size of your output is O(n) therefore it's literally impossible to have an algorithm that populates your list any more efficient than O(n) time complexity.
You're spending a whole lot more time just printing your numbers to the screen than you actually are spending generating the list. If you really want to speed this code up, remove the
System.out.println(i);
On a separate note, I've noticed that you're using a LinkedList, If you used an array(or array-based list) it should be faster.
You could implement a List where the get(int index) method simply returns the index (or some value based on the index). The creation of the list would then be constant time (O(1)). The list would have to be immutable.
Your question isn't just about building the list, it includes deletion and re-insertion. I suspect you should be using a HashSet, maybe even a BitSet instead of a List of any kind.
I have a set A = {(1,2), (1,2,3), (2,3,4), (3,4), (1)}
I want to turn it into A={(1,2,3), (2,3,4)}, remove proper subsets from this set.
I'm using a HashSet to implement the set, 2 iterator to run through the set and check all pairs for proper subset condition using containsAll(c), and the remove() method to remove proper subsets.
the code looks something like this:
HashSet<Integer> hs....
Set<Integer> c=hs.values();
Iterator<Integer> it= c.iterator();
while(it.hasNext())
{
p=it.next();
Iterator<Integer> it2= c.iterator();
while(it2.hasNext())
{
q=it2.next();
if q is a subset of p
it2.remove();
else if p is a subset of q
{
it.remove();
break;
}
}
}
I get a ConcurrentModificationException the 1st time i come out of the inner while loop and do a
p=it.next();
The exception is for when modifying the Collection while iterating over it. But that's what .remove() is for.
I have used remove() when using just 1 iterator and encountered no problems there.
If the exception is because I'm removing an element from 'c' or 'hs' while iterating over it, then the exception should be thrown when it encounter the very next it 2 .next() command, but I don't see it then. I see it when it encounters the it.next() command.
I used the debugger, and the collections and iterators are in perfect order after the element has been removed. They contain and point to the proper updated set and element. it.next() contains the next element to be analyzed, it's not a deleted element.
Any ideas over how i can do what i'm trying to do without making a copy of the hashset itself and using it as an intermediate before I commit updates?
Thank you
You can't modify the collection with it2 and continue iterating it with it. Just as the exception says, it's concurrent modification, and it's not supported.
I'm afraid you're stuck with an intermediate collection.
Edit
Actually, your code doesn't seem you make sense: are you sure it's a collection of Integer and not of Set<Integer>? In your code p and q are Integers, so "if q is a subset of p" doesn't seem to make too much sense.
One obvious way to make this a little smarter: sort your sets by size first, as you go from largest to smallest, add the ones you want to keep to a new list. You only have to check each set against the keep list, not the whole original collection.
The idea behind the ConcurrentModificationException is to maintain the internal state of the iterators. When you add or delete things from a set of items, it will throw an exception even if nothing appears wrong. This is to save you from coding errors that would end up throwing a NullPointerException in otherwise mundane code. Unless you have very tight space constraints or have an extremely large collection, you should just make a working copy that you can add and delete from without worry.
How about creating another set subsetNeedRemoved containing all subsets you are going to remove? For each subset, if there is a proper superset, add the subset to subsetNeedRemoved. At the end, you can loop over subsetNeedRemoved and remove corresponding subsets in the original set.
I'd write something like this...
PriorityQueue<Set<Integer>> queue = new PriorityQueue<Set<Integer>>(16,
new Comparator<Set<Integer>>() {
public int compare(Set<Integer> a, Set<Integer> b) {
return b.size() - a.size(); // overflow-safe!
}
});
queue.addAll(sets); // we'll extract them in order from largest to smallest
List<Set<Integer>> result = new ArrayList<>();
while(!queue.isEmpty()) {
Set<Integer> largest = queue.poll();
result.add(largest);
Iterator<Set<Integer>> rest = queue.iterator();
while(rest.hasNext()) {
if(largest.containsAll(rest.next())) {
rest.remove();
}
}
}
Yeah, it consumes some extra memory, but it's idiomatic, straightforward, and possibly faster than another approach.
i have this code, and i would like to know what the ":" mean in the function
Element[][] grid = readFile();
for (Element[] ea : grid) {
for (Element e : ea)
System.out.print(e.getChar());
System.out.println();
In terms of a language equivalent, you can think of it as the word "in". You can read it as "for each Element 'e' in 'ea'".
Here's the documentation on that type of loop: http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
When : is used in for, it acts as a for-each loop. Each iteration, the variable after the colon is assigned to the next value in the array.
int[] arr = {1,2,3,4};
for ( arr : num ) {
System.out.print( num + " " );
}
// prints "1 2 3 4 "
It's a for-each comprehension for Collections and Array. It's same as some languages like Python provide in functionality. So when you see a : in a for loop, read as in. For more details see this http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
In your case it's like for ea in grid.
This type of loop is called a 'for-each' loop. The colon (:) is read as 'in'. Basically, this type of for loop is used with collections.
It could be read as:-
for each element x in collection Y{
//do something
}
Here, in each iteration, the element x refers to the respective elements in Collection Y. i.e, in first iteration, x will be Y[0], in second iteration, x will be y[1], so on and so forth till the end.
The advantage is that condition checking and all those stuff need not be written explicitly. It is especially useful when iteration elements in a collection sequentially till the end. This makes iterating over collections quite easier. It is easier than making use of iterators.
In your code, each element of the two dimensional array 'ea' is printed, using a nested for-each loop. Outer loop iterates over each row (a single dimensional array), and inner loop iterates over each element in the respective row.
Refer these:-
For-each loop
Related question in stackoverflow
This is the new enhanced for loop.
You can read it out loud as for each Element ea in grid. It iterates over the elements in grid.
Here is a nice tutorial .
It's simply a divider between the temporary variable and the Iterable or array.
It's called a foreach loop, and basically means:
"For each element ae in Iterable grid, do {...}"
Read more here: The For-Each Loop
Iterable being an array or a list, for example.