Java foreach using reference to replace items won't work - java

In an exercice we must replace an object by another within a loop. My solution is to use the "ListIterator". But a colleague try to use the foreach syntax and play the reference but this solution won't work.
// This doesn't work
for ( Growable growable : growables ) {
growable = growable.grow(); // Return another object (seed -> sprout, ..)
}
// But that well
for (final ListIterator<Growable> it = growables.listIterator(); it.hasNext();) {
it.set(it.next().grow());
}
From the documentation[1], I can read that the foreach is not suitable for replacement because we don't have a reference to the iterator.
The program needs access to the iterator in order to remove the current element. The for-each loop hides the iterator, so you cannot call remove. Therefore, the for-each loop is not usable for filtering. Similarly it is not usable for loops where you need to replace elements in a list or array as you traverse it.
But we have a reference to the iterated object. Am I wrong ?
Can someone explain me why the "foreach" solution isn't working ?
Thanks
[1] http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html

In your first snippet, you take an element from growables and assign it to growable. This means that the variable growable references that element.
If you reassign growable, it starts referencing another object. But that doesn't change the object from growables.
To understand what's going on, you could compare this with an array. Using foreach syntax:
int[] array = {1, 2, 3};
for (int x : array) {
x = 0;
}
System.out.println(array[0]);
This will print 1. The reason is that this snippet is equivalent to
int[] array = {1, 2, 3};
for (int i = 0; i < array.length; i++) {
int x = array[i];
x = 0;
}
System.out.println(array[0]);
Now it's more obvious that assignment to x does not modify array.

In the foreach case, growable is just assigned a value, which will be forgotten in the next step as a new iteration will happen and growable's value will be overwritten with the next element in growables

Related

Array contains element in Java

I've got a task of writing a function that returns integers which are in both two arrays.
For example: nums1 [1,2,3] and nums2 [2,3,5] and answer should be [2,3].
I came with this solution:
public static void main(String[] args) {
System.out.println(arraysIntersection(new int[] {1,2,3}, new int[] {2,3,5}));
}
public static List<Integer> arraysIntersection(int[] nums1, int[] nums2) {
List<Integer> answer = new ArrayList<>();
for (int i = 0; i < nums1.length; i++) {
if (Arrays.asList(nums2).contains(nums1[i])) {
answer.add(nums1[i]);
}
}
return answer;
}
however it seems this condition doesn't work as intended:
if (Arrays.asList(nums2).contains(nums1[i]))
It says it doesn't contain the value altough it clearly contains 2 and 3. Any ideas?
I know I could just iterate each i over the second array but I thought this solution would be faster. Does anyone knows why it's not working?
You can do it in O(NlogN) time complexity and O(n) memory. Just sort arrays and use two pointers technique.
List<Integer> answer = new ArrayList<>();
int j = 0;
Arrays.sort(nums1);
Arrays.sort(nums2);
for(int i = 0; i < nums1.length; i++) {
if(i > 0 && nums1[i] == nums1[i - 1]) //we have already processed this number
continue;
while(j < nums2.length && nums2[j] < nums1[i])
j++;
if(j < nums2.length && nums1[i] == nums2[j])
answer.add(nums1[i]);
}
return answer;
You can do it in O(N) time complexity and O(n) memory (but constant is higher). Just add all elements of nums1 in first HashSet and all elements of nums2 if another HashSet. Then you can for each element in first set check if another set contains this element using O(1)* time.
List<Integer> answer = new ArrayList<>();
Set<Integer> set1 = new HashSet<>(), set2 = new HashSet<>();
set1.addAll(nums1);
set2.addAll(nums2);
for(var el : set1) {
if(set2.contains(el)) {
answer.add(el);
}
}
return answer;
*O(1) is middle time of operations with hashset
If Arrays is a static object already initialized, or declared at global scope, it may be OK, I don't know for sure. Can't call asList() on an uninitialized object, it must be allocated first.
Now I know, Arrays is a member of the utils package, can be OK.
But not anything that looks fine in code, actually works also.
As a matter of fact, I don't like the way in which Java calls a function. But it would be more easier and handy like this.
I don't know, if you had included the util package in your code.
util, or utils ? Can be 2 different packages, this is important.
You can try another way:
import java.util.*;
public static List<Integer> arraysIntersection(int[] nums1, int[] nums2){
List<Integer> answer = new ArrayList<>();
for (int i = 0; i < nums1.length; i++) {
int u = nums1[i];
for (int j = 0; j < nums2.length; j++) {
if (u == nums2[j]) {
answer.add(u);
break;
}
}
}
return answer;
}
A break could be necessary, if the values must be added only once.
( a number can be found more times into an array )
The break was meant just for ending the inner loop.
The outer loop should continue up to the end of the search.
But the same number can be find more times in the first array.
Before returning the answer, the result should be checked for duplicate values. And this is another problem.
It would be more convenient to check before adding number to list.
Check if the answer list already contains the number value.
And then add the number to the list, if a match is not found.
So this can be done more easier:
if (!answer.contains(u)) answer.add(u);
Since you check this condition, the break is not anymore needed.
But searching the list so many times, can slow down your code.
From this reason, the u value is read only once, before starting to compare with the another array. So you don't have to read manytimes the same array item, just store it in a temporary variable, u.
In another point of view, when iterating over a collection object,
the current value for the current position index could change.
It also depends on the basic interface implementation for this object.
If this function would have been written in C, it would have been a very serious problem, to get the value of an item in array, because the current position of the pointer changes. And here is the same, the current read value changes, excepting that we can't see all the underlying mechanism. And if I am not wrong too much, the original Java first time was based also on the C code.
Best regards, Adrian Brinas.
Have a nice day.

Any known negative effects of method call inside advanced for-each header (for element : method_returning_array())?

When using for-each loop I often do not create a temporary variable like
int[] arr = method_returning_array();
for (element : arr) {
// whatever
{
Instead, I shortcut it as follows:
for (element : method_returning_array()) {
// whatever
{
Is the latter way of doing it bad (or not optimal) for any reason?
If method_returning_array() returns large array read the footnote too.
Enhanced for loop is just a syntactic sugar, it can take any subtype of Iterable or Array.
In your case, since method is returning array it will be compiled as:
Let L1 ... Lm be the (possibly empty) sequence of labels immediately preceding the enhanced for statement. Then the meaning of the enhanced for statement is given by the following basic for statement:
T[] a = Expression;
L1: L2: ... Lm:
for (int i = 0; i < a.length; i++) {
VariableModifiersopt Type Identifier = a[i];
Statement
}
Where a and i are compiler-generated identifiers that are distinct from any other identifiers (compiler-generated or otherwise) that are in scope at the point where the enhanced for statement occurs.
And method_returning_array() is only called once.
IMPORTANT:
But there is a related bug,2 which got fixed in Java 10, which may impact you if method_returning_array() returns really large array. Workaround is to use traditional for loop:
for (int i = 0; i < a.length; i++)
For details, read
Actually in both cases you create temporary local to the for loop variable.
int[] arr = method_returning_array();
for (int element : arr) {
// whatever
}
arr is available after for loop
for (int element : method_returning_array()) {
// whatever
}
method_returning_array() result is not available after for loop

Check if array does NOT contain a certain value

I know that if I want to check if an array does contain a certain value I should use Arrays.asList(arrayName).contains(valueName).
But how do I check if that value is not present? At first I just thought of putting ! in front like:
!Arrays.asList(arrayName).contains(valueName)
but that doesn't seem to work.
I even tried writing the if statement like this:
if (Arrays.asList(arrayName).contains(valueName)==false)
but that doesn't seem to work either.
Here is the code:
public int[] duplikati(int[] tabela){
int len = tabela.length;
int c = 0;
int[] count = new int[len];
for (int i=0;i<len;i++){
if (Arrays.asList(count).contains(tabela[i])==false){
c++;
}
}
int[] result = new int[c];
int d = 0;
for (int j=0;j<len;j++){
if (Arrays.asList(result).contains(tabela[j])==false){
System.out.print(tabela[j]+" ");
result[d] = tabela[j];
d++;
}
}
return result;
}
In, this specific case when you pass an array of primitive types into Arrays.asList you'll get back a List with a single element which is the provided array.
So, when you do:
Arrays.asList(arrayName).contains(valueName)
The call Arrays.asList(arrayName) will return a List<int[]> and then when you call contains the valueName will get boxed to an Integer and then get's compared with the element(s) in the list. because an int[] is never equal to an integer value, the contains call will always return false.
Solution 1 - change the type of your arrays from int[] to Integer[], then everything should work as you expect.
Solution 2 - Assuming you do not want to change the type of the arrays for some reason, then you can do:
final int index = i;
if(Arrays.stream(count).noneMatch(e -> e == tabela[index])){...}
inside the for loops.
You can think of the noneMatch method as !Arrays.asList(someArray).contains(someValue) if it helps.
Similarly, you can check if the array contains an element with:
final int index = i;
if(Arrays.stream(count).anyMatch(e -> e == tabela[index])){...}
You can think of the anyMatch method as Arrays.asList(someArray).contains(someValue) if it helps.
You can use Java 8 stream api as follows
Integer arr[]=new Integer[]{1,2,30,61};
System.out.println(Arrays.asList(arr).stream().noneMatch(element>element==10));
You can go through the below link for explaination of
noneMatch()

Remove an object from an ArrayList without (implicitly) looping through it

I am looping through a list A to find X. Then, if X has been found, it is stored into list B. After this, I want to delete X from list A. As speed is an important issue for my application, I want to delete X from A without looping through A. This should be possible as I already know the location of X in A (I found its position in the first line). How can I do this?
for(int i = 0; i<n; i++) {
Object X = methodToGetObjectXFromA();
B.add(X);
A.remove(X); // But this part is time consuming, as I unnecessarily loop through A
}
Thanks!
Instead of returning the object from yhe method, you can return its index and then remove by index:
int idx = methodToGetObjectIndexFromA();
Object X = A.remove(idx); // But this part is time consuming, as I unnecessarily loop through A
B.add(X);
However, note that the remove method may be still slow due to potential move of the array elements.
You can use an iterator, and if performance is an issue is better you use a LinkedList for the list you want to remove from:
public static void main(String[] args) {
List<Integer> aList = new LinkedList<>();
List<Integer> bList = new ArrayList<>();
aList.add(1);
aList.add(2);
aList.add(3);
int value;
Iterator<Integer> iter = aList.iterator();
while (iter.hasNext()) {
value = iter.next().intValue();
if (value == 3) {
bList.add(value);
iter.remove();
}
}
System.out.println(aList.toString()); //[1, 2]
System.out.println(bList.toString()); //[3]
}
If you stored all the objects to remove in a second collection, you may use ArrayList#removeAll(Collection)
Removes from this list all of its elements that are contained in the
specified collection.
Parameters:
c collection containing elements to be removed from this list
In this case, just do
A.removeAll(B);
When exiting your loop.
Addition
It calls ArrayList#batchRemove which will use a loop to remove the objects but you do not have to do it yourself.

How to remove element from an array

I have an array for example:
String [][] test = {{"a","1"},
{"b","1"},
{"c","1"}};
Can anyone tell me how to remove an element from the array. For example I want to remove item "b", so that the array looks like:
{{"a","1"},
{"c","1"}}
I can't find a way of doing it. What I have found here so far is not working for me :(
You cannot remove an element from an array. The size of a Java array is determined when the array is allocated, and cannot be changed. The best you can do is:
Assign null to the array at the relevant position; e.g.
test[1] = null;
This leaves you with the problem of dealing with the "holes" in the array where the null values are. (In some cases this is not a problem ... but in most cases it is.)
Create a new array with the element removed; e.g.
String[][] tmp = new String[test.length - 1][];
int j = 0;
for (int i = 0; i < test.length; i++) {
if (i != indexOfItemToRemove) {
tmp[j++] = test[i];
}
}
test = tmp;
The Apache Commons ArrayUtils class has some static methods that will do this more neatly (e.g. Object[] ArrayUtils.remove(Object[], int), but the fact remains that this approach creates a new array object.
A better approach would be to use a suitable Collection type. For instance, the ArrayList type has a method that allows you to remove the element at a given position.
There is no built-in way to "remove" items from a regular Java array.
What you want to use is an ArrayList.
You could set the entry in the array to null (test[0][1] = null;). However, "removing" the item such that the array will have one element less than before is not doable without recreating the array. If you plan to change data in the data structure regularly an ArrayList (or another Collection class depending on your needs) might be more convenient.
My solution is:
You cannot remove an element from an array => it's correct, but we can do something to change current array.
No need assign null to the array at the relevant position; e.g.
test[1] = null;
Create a new array with the element removed; e.g.
String[][] temp = new String[test.length - 1][];
Need to get index at string/array to remove: IndexToRemove
for (int i = 0; i < test.length-1; i++) {
if (i<IndexToRemove){
temp[i]=test[i];
}else if (i==IndexToRemove){
temp[i]=test[i+1];
}else {
temp[i]=test[i+1];
}
}
test = temp;
Hope it helpful!

Categories