Enhanced for loop starting part way through List - java

Im a beginner in Java and I had this doubt. Is it possible to use the Enhanced for loop in Java on an ArrayList, but start at the specified point rather than ArrayList[0].
For eg. ArrayList<Integer> calc = new ArrayList<Integer>;
// calc contains {0,1,2,3,4,5,6,7}
Can I use enhanced for loop and start iterating from calc[2] rather than calc[0]?? If possible, how can I do that?
In my particular case, using a enhanced for loop would be better, rather than a normal for loop.

The best way in Java would be like this:
for (Integer i : calc.subList(start, calc.size()) {
...
}
subList is an efficient view of the original list, so it's almost exactly what you need.
UPDATE
OK, motivated by Mikera's comments, I benchmarked it on jmh. This is the benchmarked code:
import org.openjdk.jmh.annotations.GenerateMicroBenchmark;
public class Benchmark1
{
static final List<Integer> list = new ArrayList(asList(1,2,3,4,5,6,7,8,9,10));
static { for (int i = 0; i < 5; i++) list.addAll(list); }
#GenerateMicroBenchmark
public long testIterator() {
long sum = 0;
for (int i : list) sum += i;
return sum;
}
#GenerateMicroBenchmark
public long testIndexed() {
long sum = 0;
for (int i = 0; i < list.size(); i++) sum += list.get(i);
return sum;
}
#GenerateMicroBenchmark
public long testSublistIterator() {
long sum = 0;
for (int i : list.subList(1, list.size())) sum += i;
return sum;
}
#GenerateMicroBenchmark
public long testIndexedSublist() {
long sum = 0;
final List<Integer> l = list.subList(1, list.size());
for (int i = 0; i < l.size(); i++) sum += l.get(i);
return sum;
}
}
And these are the results:
Benchmark ops/msec
-------------------------
Indexed 1860.982
IndexedSublist 1642.059
Iterator 1818.657
SublistIterator 1496.994
Conclusions:
enhanced for on the main list is as fast as indexed iteration, once past the initialization cost;
traversal of the sublist is somewhat slower than of the main list, and iteration is somewhat slower than indexed traversal;
all the differences are negligible for all practical purposes.

You're stuck using a traditional loop here...
for (int i = 2; i < calc.size(); i++) {
Integer x = calc.get(i);
}
Well, unless you're willing to create a temporary subList just for using an enhanced for loop, which is fine, because sublists are views of the original list and don't create a new list object:
for (Integer x : calc.subList(2, calc.size())) {
}

for(Item e : list.subList(1, list.size())) {
// ...
}

You could iterate through the sublist, as below:
for (Integer integerMember : calc.subList(2, calc.size()) {
// operation here
}

It should be noted that the enhanced for loop is less efficient for ArrayList then standard indexing. This is because we have to create an Iterator object and call hasNext and next on it on each step of the loop, causing unnecessary overhead.
For this reason I would recommend indexing in the traditional way rather than using the sublist approach.

Related

Search fast an element in array of java.util.LinkedList

Hey I am searching for a better method to search a String element in an array of LinkedLists.
public static void main(String[] args) {
int m = 1000;
LinkedList<String>[] arrayOfList = new LinkedList[m];
for (int i = 0; i < m; i++) {
arrayOfList[i] = new LinkedList<>();
}
}
This is my search method:
public int search(String word) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < arrayOfList[i].size(); j++) {
if (arrayOfList[i].get(j).equals(word)) {
return i;
}
}
}
return -1;
}
This is how my LinkedLists look like:
Example output: arrayOfList[0] = [house,car,tree.....]
arrayOfList[1] = [computer,book,pen....]
......
until arrayOfList[1000] = [...]
My search method should find the index of my word. Example: search("computer") = 1; search("house") = 0
Ah, a classic!
LinkedList is notoriously bad for random access, i.e. the list.get(j) method.
It's much better at iterating through the list, so it can jump from each item to the next item.
You could use list.iterator(), but the foreach loop does the same thing:
public int search(String word) {
for (int i = 0; i < m; i++) {
for (String listValue: arrayOfList[i]) {
if (listValue.equals(word)) {
return i;
}
}
}
return -1;
}
The other answer notes that you can get much better performance by iterating over each LinkedList rather than using List.get. That's because List.get has to search from the start of the list each time. For example, if the LinkedList has 100 elements, then on average each call to List.get(j) will have to iterate over 50 elements, and you're doing that 100 times. The foreach loop just iterates over the LinkedList elements once.
The foreach strategy runs in O(n) time, that is, the time required to perform the lookup increases proportional to n, the total number of words, because you have to search them all for each word.
If you're going to be doing this a lot, and you can use data structures other than LinkedList, then you should iterate through your array of LinkedList once and build a HashMap where the key is the word and the value is the number of the array in which that word appears. Setting up this HashMap will require O(n) time, but subsequent lookups will only require O(1) time, meaning a constant time regardless of the number of words involved. So if you're going to do more than a single lookup, creating the HashMap will have better performance in big-O terms, although for a very small number of lookups (2 or 3) it may still be faster to scan the arrays.
You can build a HashMap like this:
Map<String, Integer> index = new HashMap<>();
for (int i = 0; i < m; i++) {
for (String word: arrayOfList[i]) {
index.put(word, i);
}
}
Now search just becomes:
public int search(String word) {
return index.getOrDefault(word, -1);
}
Depending on how the strings are constructed in your program and how often you call the search method, testing on your strings' hash code can improve the performance. ex:
public int search(String word) {
int wordHashCode = word.hashCode();
for (int i = 0; i < m; i++) {
for (String listValue: arrayOfList[i]) {
if (listValue.hashCode() == wordHashCode && listValue.equals(word)) {
return i;
}
}
}
return -1;
}

How can I fix my java quick sort?

The problem is, it's a neverending recursion. I don't know, how can I finish the recursion. The funny is, it works, if I print the arraylist (mergedArray), it will be sorted after some iteration, but the function never stops.
The error message is:
"at javaapplication9.QuickSort.simple_quick_sort(QuickSort.java:40)"
The code below:
public ArrayList<Integer> simple_quick_sort(ArrayList<Integer> arr) {
ArrayList<Integer> mergedArray = new ArrayList<Integer>();
ArrayList<Integer> left = new ArrayList<Integer>();
ArrayList<Integer> right = new ArrayList<Integer>();
if (arr.size() <= 1) {
return arr;
}
else {
int pivot = arr.get(0);
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i) < pivot) {
left.add(arr.get(i));
}
else {
right.add(arr.get(i));
}
}
}
mergedArray.addAll(left);
mergedArray.addAll(right);
simple_quick_sort(mergedArray);
return mergedArray;
}
public ArrayList<Integer> simple_quick_sort(ArrayList<Integer> arr) {
if (arr.size() <= 1) {
return arr;
}
else {
ArrayList<Integer> mergedArray = new ArrayList<Integer>();
ArrayList<Integer> left = new ArrayList<Integer>();
ArrayList<Integer> right = new ArrayList<Integer>();
int pivot = arr.get(0);
for (int i = 0; i < arr.size(); i++) {
if (arr.get(i) < pivot) {
left.add(arr.get(i));
left = simple_quick_sort(left);
}
else {
right.add(arr.get(i));
right = simple_quick_sort(right);
}
}
}
mergedArray.addAll(left);
mergedArray.addAll(right);
}
Of course, copying is contrary to the basic idea of quicksort which is good because it can work on the array to be sorted, not requiring these copy operations and storage allocations.
I am sorry but your entire implementation of quicksort is kind of incorrect. Also, using a loop inside of a recursive function negates the benefits of using recursion. If you want to implement that loop, I would suggest you nest it inside another loop to make the code simpler (won't be as efficient as recursion).
If you want to continue with this program, try making the following change:
When you write
simple_quick_sort(mergedArray);
return mergedArray;
you are not using the returned value from the function. You are just calling the function and doing nothing with the returned value. There might be more things that need fixing before this code works.
If you want to learn more about quick sort and recursion, I found this page http://www.geeksforgeeks.org/quick-sort/
I hope this helps!

Keep going out of bounds ArrayList

I have a program I have to do in my comp sci class that is about keep track of cookie orders (think girl scout cookies). Here is a method designed to remove a certain variety of cookie and return the number of boxes removed. It keeps going out of bounds. The ArrayList is the "orders" variable it is made up of CookieOrder object(CookieOrder class below)
public int removeVariety(String cookieVar)
{
int counter = 0;
for(int i = orders.size() - 1; i > 0; i--)
{
if(orders.get(i).getVariety().equals(cookieVar))
{
counter += orders.get(i).getNumBoxes();
orders.remove(i);
}
}
return counter;
}
Here's the CookieOrder class
private String variety;
private int boxes;
public CookieOrder (String variety, int numBoxes)
{
this.variety = variety;
boxes = numBoxes;
}
public String getVariety()
{
return variety;
}
public int getNumBoxes()
{
return boxes;
}
Don't use for loop, use an iterator and use the Iterator#remove()
You initialize the for loop variable to start from orders.size() and go down to 0. But inside the loop you remove orders, so orders.size() is decreased but the loop variable i will not notice it.
The simplest solution is to loop from 0 to orders.size() - 1 - it will be evaluated every time, so it will notice the removal.
The problem is you are modifying the list as you are looping through it at the same time. That's not going to work. If you just want to sum up some value, you don't need to remove the item from the list.
Hope this helps
Try this instead note you should really use an Iterator but I think you will not have covered that yet in your course. Specifically note the difference between i > 0 and i >= 0:
public int removeVariety(String cookieVar)
{
int counter = 0;
for (int i = orders.size() - 1; i >= 0; i--)
{
CookieOrder o = orders.get(i);
if (o.getVariety().equals(cookieVar))
{
counter += o.getNumBoxes();
orders.remove(i);
}
}
return counter;
}
What you are doing is basically traversing the list in reverse order, so that the removed elements do not affect the indices of the remaining elements.
Alternative iterator based solution
If your curious here is a solution that uses an iterator:
public int removeVariety(String cookieVar)
{
int counter = 0;
Iterator iter = orders.iterator();
while (iter.hasNext())
{
CookieOrder o = iter.next();
if (o.getVariety().equals(cookieVar))
{
counter += o.getNumBoxes();
iter.remove();
}
}
return counter;
}
If you are using Java 8:
return orders.stream()
.filter(ord -> ord.getVarienty().equals(cookieVar))
.peek(orders::remove)
.mapToInt(ord -> ord.getNumBoxes())
.sum();
or using iterator (more imperative way):
int c = 0;
Iterator<CookieOrder> it = orders.iterator();
while (it.hasNext()) {
CookieOrder current = it.next();
if(current.getVarienty().equals(cookieVar)){
it.remove();
c += current.getNumBoxes();
}
}
return c;
What you were trying to do is to bite your own tail here :)
Do not modify a collection that you are currently processing.

For loop - like Python range function

I was wondering if in Java there is a function like the python range function.
range(4)
and it would return
[0,1,2,3]
This was an easy way to make for enhanced loops. It would be great to do this in Java because it would make for loops a lot easier. Is this possible?
Java 8 (2014) has added IntStream (similar to apache commons IntRange), so you don't need external lib now.
import java.util.stream.IntStream;
IntStream.range(0, 3).forEachOrdered(n -> {
System.out.println(n);
});
forEach can be used in place of forEachOrdered too if order is not important.
IntStream.range(0, 3).parallel() can be used for loops to run in parallel
Without an external library, you can do the following. It will consume significantly less memory for big ranges than the current accepted answer, as there is no array created.
Have a class like this:
class Range implements Iterable<Integer> {
private int limit;
public Range(int limit) {
this.limit = limit;
}
#Override
public Iterator<Integer> iterator() {
final int max = limit;
return new Iterator<Integer>() {
private int current = 0;
#Override
public boolean hasNext() {
return current < max;
}
#Override
public Integer next() {
if (hasNext()) {
return current++;
} else {
throw new NoSuchElementException("Range reached the end");
}
}
#Override
public void remove() {
throw new UnsupportedOperationException("Can't remove values from a Range");
}
};
}
}
and you can simply use it like this:
for (int i : new Range(5)) {
System.out.println(i);
}
you can even reuse it:
Range range5 = new Range(5);
for (int i : range5) {
System.out.println(i);
}
for (int i : range5) {
System.out.println(i);
}
As Henry Keiter pointed out in the comment below, we could add following method to the Range class (or anywhere else):
public static Range range(int max) {
return new Range(max);
}
and then, in the other classes we can
import static package.name.Range.range;
and simply call
for (int i : range(5)) {
System.out.println(i);
}
Um... for (int i = 0; i < k; i++)? You don't have to write enhanced for loops all day, you know, although they are cool...
And just for the sake of argument:
for (int i : range(k)) char count: 22
for (int i = 0; i < k; i++) char count: 27
Discounting the implementation of range, it is pseudo even.
Use Apache Commons Lang:
new IntRange(0, 3).toArray();
I wouldn't normally advocate introducing external libraries for something so simple, but Apache Commons are so widely used that you probably already have it in your project!
Edit: I know its not necessarily as simple or fast as a for loop, but its a nice bit of syntactic sugar that makes the intent clear.
Edit: See #zengr's answer using IntStream in Java 8 .
If you really, really want to obtain an equivalent result in Java, you'll have to do some more work:
public int[] range(int start, int end, int step) {
int n = (int) Math.ceil((end-start)/(double)step);
int[] arange = new int[n];
for (int i = 0; i < n; i++)
arange[i] = i*step+start;
return arange;
}
Now range(0, 4, 1) will return the expected value, just like Python: [0, 1, 2, 3]. Sadly there isn't a simpler way in Java, it's not a very expressive language, like Python.
Its not available that true. But you make a static method and use it -
public static int[] range(int index){
int[] arr = new int[index];
for(int i=0;i<index;i++){
arr[i]=i;
}
return arr;
}
As far as I know, there's not an equivalent function in java. But you can write it yourself:
public static int[] range(int n) {
int[] ans = new int[n];
int i;
for(i = 0; i < n; i++) {
ans[i] = i;
}
return ans;
}
There's no Java equivalent to the range function, but there is an enhanced for-loop:
for (String s : strings) {
// Do stuff
}
You could also roll your own range function, if you're really attached to the syntax, but it seems a little silly.
public static int[] range(int length) {
int[] r = new int[length];
for (int i = 0; i < length; i++) {
r[i] = i;
}
return r;
}
// ...
String s;
for (int i : range(arrayOfStrings.length)) {
s = arrayOfStrings[i];
// Do stuff
}
What you can do to substitute the range in python in java can be done with the following code. NOTE: I am not going off of your code, I am just writing a small piece of code and showing it to you.
in python you would do.. . .
if -2 <= x <= 10:
print(x)
in java you would substitute this range and do. . ..
if(x >= -2 && x <= 10){
System.out.println("x")
}
By doing the above code in java, you don't need a range, but you have the
-2 <= x <=10 range and split it into x >= -2 and x <= 10. It means the same thing, but the one I explained in java may take the compiler a longer time to read. So if you are using python go with the former's code format, and if you are using java, use the latter's code format.

How can I find two repeating elements in an Array

Below code works fine but it is in the complexity of O(n^2). Is it possible to do it O(n) or O(log n) time.
public class TwoRepeatingElements {
public static void main(String[] args) {
Integer array[] = {4, 2, 4, 5, 2, 3, 1, 2};
findTwoRepeatingElements(array);
}
private static void findTwoRepeatingElements(Integer[] array) {
int i, j;
for(i = 0; i < array.length-1; i++) {
for(j = i+1; j < array.length-1; j++) {
if(array[i] == array[j]) {
System.out.println(array[i]);
}
}
}
}
}
Obviously you can't find it in less than O(n), since you need to scan the whole array.
You can use hastable for a O(n) solution.
Just insert your elements in a hastable as you go and stop when the element you are to insert is already there.
private static void findTwoRepeatingElements(Integer[] array) {
Set<Integer> set = new HashSet<Integer>();
for(int a : array) {
if(!set.add(a)) {
System.out.println(a);
break;
}
}
}
You can sort the array and then just look for two equal numbers in adjacent positions.
This solution runs in O(n) time, notice that if you only need to find one repeated element, you can exit the loop as soon as you find it:
private static void findTwoRepeatingElements(Integer[] array) {
Set<Integer> seen = new HashSet<Integer>();
for (Integer i : array) {
if (seen.contains(i))
System.out.println(i);
else
seen.add(i);
}
}
EDIT
If you need to print the repeated elements only once, this solution uses a little more memory since two sets are needed, but it's still O(n). Take a look at this:
private static void findTwoRepeatingElements(Integer[] array) {
Set<Integer> seen = new HashSet<Integer>();
Set<Integer> repeated = new HashSet<Integer>();
for (Integer i : array)
if (!seen.add(i) && repeated.add(i))
System.out.println(i);
}
Create a temporary hashmap and put all values you encounter into this. The average look up time for a hashmap is O(1), thus you'd end with O(n).
O(log n) is absolutely impossible, since you need to iterate over the entire array at least once.
If you know beforehand what range of integers are possible, and it's a relatively small range, you can use a boolean[] to keep track of what integers you've already seen. That would be O(n+k), where k is the size of the range, and therefore O(n) if k is in O(n). Otherwise, you can use a HashSet<Integer>, though that would not be guaranteed O(n) time.
This can be reduced to O(n)
int previous =array[0];
for(int i=1; i less than array.length; i++) {
if (previous == array[i] return true;
previous =array[i];
}
return false // outside of loop.
Forgive the formatting I'm on my mobile
Similar to Peter's answer, but using the API better and thus with less code:
static Integer findFirstRepeatedElement(Integer[] array) {
Set<Integer> set = new HashSet<Integer>();
for(Integer a : array) {
if(!set.add(a)) // returns false if the element is already in the set
return a;
}
return null;
}
Edited: I notice he has now fixed his previous non-leet implementation

Categories