Why do I need to create an array many times? - java

This programm shuffles a source list by pairs. So that original list
"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"
trasfoms to
11^12 19^20 17^18 15^16 1^2 5^6 3^4 13^14 7^8 9^10
The above is true while commented line is uncommented. Now, if line A is commented then all the elements in shuffleList are 19^20.
public class ShuffleService {
public static void shuffleList(List<String> list) {
System.out.println(list);
ArrayList<String[]> shuffleList = new ArrayList<String[]>(10);
String[] arr = new String[2];
boolean flag = false;
int step = 0;
for(String s: list){
if(flag){
arr[1]=s;
} else {
arr[0]=s;
}
flag=!flag;
step++;
if(step==2){
shuffleList.add(arr);
step=0;
//arr = new String[2]; //**line A**
}
}
Collections.shuffle(shuffleList);
for(String[] val: shuffleList){
System.out.print(val[0]);
System.out.print("^");
System.out.println(val[1]);
}
}
public static void main(String[] args) {
String[] a = new String[]{"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20"};
List<String> list1 = Arrays.asList(a);
shuffleList(list1);
}
}
So why do I need to uncomment line A in the program to work properly?

Because when you rewrite the values to arr (without remaking it), you're also going to modify the values already in the list.
Adding an object to the list doesn't stop you from modifying it, it will not make copies on its own. By calling new String[2] in your loop you're effectively building a new string array for each pair that you add to the list, which is what you want.

Related

Why changes in sublist are reflected in the original list in Java... how to avoid this?

// "static void main" must be defined in a public class.
import java.util.*;
public class Main {
static void func(ArrayList<ArrayList<Integer>> arr) {
ArrayList<Integer> arr1 = new ArrayList();
arr1.add(0);
arr.add(arr1);
arr1.set(0,5);
}
public static void main(String[] args) {
ArrayList<ArrayList<Integer>> arr = new ArrayList<ArrayList<Integer>>();
func(arr);
for(int i=0;i<arr.size();i++) {
for(int j=0;j<arr.get(i).size();j++) {
System.out.print(arr.get(i).get(j));
}
System.out.println();
}
}
}
In the above code, we add an 1D arraylist of 1 element (0) to the 2D arraylist arr, but when we change the value in the 1D arraylist from 0 to 5, why is the same change reflected in the 2d arraylist, and most importantly, how exactly do we avoid this?
By default, Java Lists are mutable and you can easily change their content by adding or removing elements. In addition to this, your arr List has a reference to arr1 and not a copy of it. This means that whenever you change 1D this change is also reflected in arr because both arr1 and the content of arr reference to the same exact List.
One way to avoid this is actually copying the arr1 List before adding it to arr as follows:
static void func(ArrayList<ArrayList<Integer>> arr) {
ArrayList<Integer> arr1 = new ArrayList<>();
arr1.add(0);
arr.add(new ArrayList<>(arr1));
arr1.set(0,5);
}
public static void main(String[] args) {
ArrayList<ArrayList<Integer>> arr = new ArrayList<ArrayList<Integer>>();
func(arr);
for(int i=0;i<arr.size();i++) {
for(int j=0;j<arr.get(i).size();j++) {
System.out.print(arr.get(i).get(j));
}
System.out.println();
}
}
Mind the changed line arr.add(new ArrayList<>(arr1));. This guarantees that the reference that arr holds is different than the reference of the original arr1. You are basically creating a new List.
Although this fixes your case, it might not work for every List because it depends on its content. This works on your case because Integer is an immutable class, but if you would have a List of a mutable class, then this wouldn't be enough because both Lists would reference exactly the same objects. An example of this is below:
public static void main(String[] args) {
ArrayList<ArrayList<MutableClass>> arr = new ArrayList<>();
ArrayList<MutableClass> arr1 = new ArrayList<>();
arr1.add(new MutableClass("original"));
arr.add(new ArrayList<>(arr1));
System.out.println(arr.get(0));
// now let's change the property of arr1 MutableClass to something else
arr1.get(0).setProperty("changed");
System.out.println(arr.get(0));
}
public static class MutableClass {
private String property;
public MutableClass(String property) {
this.property = property;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
#Override
public String toString() {
return "MutableClass{" +
"property='" + property + '\'' +
'}';
}
}
As you can see by running the code, changing the object in arr1, also changes the object in arr even if you create a new List. The only way to overcome this is by making MutableClass immutable or by deep copying the original arr1 List before adding it to arr. This means you would need to copy every single object inside arr1 as follows:
public static void main(String[] args) {
ArrayList<ArrayList<MutableClass>> arr = new ArrayList<>();
ArrayList<MutableClass> arr1 = new ArrayList<>();
arr1.add(new MutableClass("original"));
ArrayList<MutableClass> copiedList = new ArrayList<>();
for (MutableClass object : arr1) {
copiedList.add(new MutableClass(object));
}
arr.add(copiedList);
System.out.println(arr.get(0));
// now let's change the property of arr1 MutableClass to something else
arr1.get(0).setProperty("changed");
System.out.println(arr.get(0));
}
public static class MutableClass {
private String property;
public MutableClass(String property) {
this.property = property;
}
public MutableClass(MutableClass other) {
this.property = other.property;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
#Override
public String toString() {
return "MutableClass{" +
"property='" + property + '\'' +
'}';
}
}
To avoid 5 getting reflected in 2D list
create a new array list from arr1 in method func() and add it to arr(the 2D list) as shown below.
static void func(ArrayList<ArrayList<Integer>> arr) {
ArrayList<Integer> arr1 = new ArrayList();
arr1.add(0);
arr.add(new ArrayList<>(arr1));
arr1.set(0,5);
}
The reason for the behaviour:
Java is pass by value
When we do
func(arr);
in main method, the reference to the actual array list object in heap is passed as value to the method "func()".
Inside func, hence arr will be pointing to the same object.
When we add the array list newly created arr1 into arr, the reference to actual object corresponding to arr1 gets added to the actual 2D array.
This is because both arr of func() as well as arr of main() refers to same object in heap.
When we try to change something in arr1 list,
it is referenced by arr. So, it will be still visible to arr.
Printing the list in main gives output 5.
But when we create a new array list and add that to arr in func(), as below
arr.add(new ArrayList<>(arr1));
then the list got added to arr will be different from arr1.
Hence,
while printing in main(),
the 2D list holds the reference to newly created array list
(ie; new ArrayList<>(arr1)).
So, it will not get affected by changing to 5 by the line
arr1.set(0,5);
This will still give 0 while printing the list arr in main().

Check if an arrayList contains an array

I have an arrayList that contains arrays. How do I check if the arrayList contains a specified array? I used .contains method and it returns false instead of expected true.
import java.util.ArrayList;
import java.util.Arrays;
public class main {
public static void main(String[] args) {
ArrayList<String[]> action = new ArrayList<String[]>();
action.add(new String[]{"appple", "ball"});
String[] items = new String[]{"appple", "ball"};
if (action.contains(new String[]{"appple", "ball"})) {
System.out.println("Yes");
}
System.out.println(action.contains(items)); // False
}
}
As you are creating different arrays (even if the contents are the same), contains will result false.
However, if you do this:
List<String[]> action = new ArrayList<String[]>();
String[] items = new String[]{"apple","ball"};
action.add(items);
if (action.contains(items))
System.out.println("Yes");
This will print Yes.
Also, some examples of the behaviour:
String[] items = new String[]{"apple","ball"};
action.add(items);
String[] clone = items.clone();
String[] mirror = items;
action.contains(clone); // false
action.contains(mirror); // true
items[0]="horse";
System.out.println(mirror[0]); // "horse"
System.out.println(clone[0]); // "apple"
System.out.println(action.get(0)[0]); // "horse"
mirror[1]="crazy";
System.out.println(clone[1]); // "ball"
System.out.println(action.get(0)[1]); // "crazy"
System.out.println(items[1]); // "crazy"
clone[1]="yolo";
System.out.println(action.get(0)[1]); // "crazy"
System.out.println(items[1]); // "crazy"
System.out.println(mirror[1]); // "crazy"
System.out.println(action.get(0).hashCode()); //2018699554
System.out.println(items.hashCode()); //2018699554
System.out.println(clone.hashCode()); //1311053135
System.out.println(mirror.hashCode()); //2018699554
Custom "contains"
The issue here is that if you want to search for an specific array afterwards, you'd lose the references and searching an item wouldn't be possible, not even replicating the array with the same exact values.
As a workaround, you could implement your own contains method. Something like:
If you wish to get the index:
static int indexOfArray(List<String[]> list, String[] twin)
{
for (int i=0;i<list.size();i++)
if (Arrays.equals(list.get(i),twin))
return i;
return -1;
}
And then, call it like:
String[] toSearch = new String[]{"apple","ball"};
int index = indexOfArray(action, toSearch);
if (index>0)
System.out.println("Array found at index "+index);
else
System.out.println("Array not found");
If the index is bigger than -1, you can get your original array by just:
String[] myArray = action.get(index);
HashMap + identifier
An alternative would be storing the arrays into a HashMap by declaring an identifier for each array. For example:
Base64 ID
This will give the same result for the same values, as the encoded value is based on the entries, not the Object's reference.
static String getIdentifier(String[] array)
{
String all="";
for (String s : array)
all+=s;
return Base64.getEncoder().encodeToString(all.getBytes());
}
And then you could:
Map<String, String[]> arrayMap= new HashMap<>();
String[] items = new String[]{"apple","pear", "banana"}; // *[1234]
action.add(items);
arrayMap.put(getIdentifier(items), items); // id = QUJDYWFh
//....
//Directly finding the twin will fail
String[] toSearch = new String[]{"apple","pear", "banana"}; // *[1556]
System.out.println(action.contains(toSearch)); // false
//But if we get the identifier based on the values
String arrId = getIdentifier(toSearch); // id = QUJDYWFh
System.out.println(action.contains(arrayMap.get(arrId))); //true
//arrayMap.get(arrId)-> *[1234]
//.....
Name.
Choose a representative name and use it as Id
Map<String, String[]> arrayMap= new HashMap<>();
String[] items = new String[]{"apple","pear", "banana"};
action.add(items);
arrayMap.put("fruits", items);
//...
System.out.println(action.contains(arrayMap.get("fruits"))); // true
The 'contains' method compares equivalent hashCode values.
So if you make it like below*, it will pass.
public class main {
public static void main(String[] args) {
ArrayList<String[]> action = new ArrayList<String[]>();
String[] items = new String[]{"appple","ball"};
action.add(items);
System.out.println("TO STRING");
System.out.println("--"+action.get(0));
System.out.println("--"+new String[]{"apple","ball"});
System.out.println("HASHCODES");
String[] sameValues = new String[]{"apple","ball"};
System.out.println("--"+action.get(0).hashCode());
System.out.println("--"+items.hashCode());
System.out.println("--"+sameValues.hashCode());
System.out.println("CONTAINS");
System.out.println("--"+action.contains(items)); // *this
System.out.println("--"+action.contains(sameValues));
System.out.println("--"+action.contains(new String[]{"apple","ball"}));
}
}
result is:
TO STRING
--[Ljava.lang.String;#7b1d7fff
--[Ljava.lang.String;#299a06ac
HASHCODES
--1243554231
--1243554231
--2548778887
CONTAINS
--true
--false
--false
Regarding the code shown when printing the array, these don't override toString(), so you get:
getClass().getName() + '#' + Integer.toHexString(hashCode())
For example:
[Ljava.lang.String;#7b1d7fff
[ stands for single dimension array
Ljava.lang.String stands for the type
#
7b1d7fff Hex representation of the hashcode
However, if you want to compare the values, there is the following method.
public class main {
public static void main(String[] args) {
String[] items = new String[]{"apple","ball"};
ArrayList<String> action = new ArrayList<>(Arrays.asList(items));
if (action.contains("apple")) {
System.out.println("Yes");
}
}
}
You can iterate over this list and for each element, i.e. array, call Arrays.equals method to check equality of arrays until first match, or till the end of the list if none match. In this case it can return true for each element:
List<String[]> list = List.of(
new String[]{"appple", "ball"},
new String[]{"appple", "ball"});
String[] act = new String[]{"appple", "ball"};
System.out.println(list.stream()
.anyMatch(arr -> Arrays.equals(arr, act))); // true
This method internally calls String#equals method for each element of the array, i.e. String, so this code also returns true:
List<String[]> list = List.of(
new String[]{new String("appple"), new String("ball")},
new String[]{new String("appple"), new String("ball")});
String[] act = new String[]{new String("appple"), new String("ball")};
System.out.println(list.stream()
.anyMatch(arr -> Arrays.equals(arr, act))); // true
According to JavaDocs, "contains" method is using "equals" and "hashCode" methods in order to check whether an object is contained.
A leading question:
Do you know what's the implementation of "equals" for arrays?
Check it and you will probably understand your code's execution result (hint: ==).
As "Hovercraft Full Of Eels" said, a better design will be using a list of some Collection which you DO understand / control it's "equals" and "hashCode" methods.

String inside ArrayList<String[]>

How to check whether a specific String is present inside ArrayList<String[]>?
Whether I need to iterate each item and check for the string or any specific method for this purpose is present (like ArrayList.contains() )?
Tried ArrayList.contains() but not working in my case.
It is not an ArrayList <String> it is ArrayList<String[]> so this question is not a duplicate one and am asking this for a curiosity whether any special method is present or not
This is a example program to get what you asked for... hope it helps
public static void main(String[] args) {
ArrayList<String []> a = new ArrayList<>();
String b[] = {"not here","not here2"};
String c[] = {"not here3","i'm here"};
a.add(b);
a.add(c);
for (String[] array : a) {// This loop is used to iterate through the arraylist
for (String element : array) {//This loop is used to iterate through the array inside the arraylist
if(element.equalsIgnoreCase("i'm here")){
System.out.println("found");
return;
}
}
}
System.out.println("match not found");
}
You can do it easily with streams:
String contains;
List<String[]> strings;
boolean isPresent = strings.stream().flatMap(Arrays::stream).anyMatch(contains::equals);
Well, you need to traverse whole list and then traverse each array inside it to find the item.
String valToBeSearched="abc";
for(String [] arr: list)
{
for(String str: arr)
{
if(str.equals(valToBeSearched)){ // do your stuff}
}
}
Using Java 8 streams, you can do this:
public boolean containsString(List<String[]> list, String s) {
// Gives you a Stream<String[]>.
return list.stream()
// Maps each String[] to Stream<String> (giving you a
// Stream<Stream<String>>), and then flattens it to Stream<String>.
.flatMap(Arrays::stream)
// Checks if any element is equal to the input.
.anyMatch(Predicate.isEqual(s));
}
You could iterate over the ArrayList with two for-each loops:
import java.util.Arrays;
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
ArrayList<String[]> arrayList = new ArrayList<String[]>();
String[] fruit = {"Apple", "Banana"};
String[] pets = {"Cat", "Dog"};
arrayList.add(fruit);
arrayList.add(pets);
System.out.println(Arrays.deepToString(arrayList.toArray())); //[[Apple, Banana], [Cat, Dog]]
System.out.println(arrayListContains(arrayList, "Apple")); //true
System.out.println(arrayListContains(arrayList, "Orange")); //false
}
public static boolean arrayListContains(ArrayList<String[]> arrayList, String str) {
for (String[] array : arrayList) {
for (String s : array) {
if(str.equals(s)) {
return true;
}
}
}
return false;
}
}
Try it here!
Try to take a look at Guava Iterables.concat().
It can be used to flatten Iterable of Iterables, i'm not sure it will work on an Iterable of Array but it's just a little transformation...
If you can flatten your list, you could then use the "contains" method on the result.

Using a returned ArrayList

I'm currently desperatly trying to get an ArrayList that I return from a function into a new ArrayList in my main function...
Here are the code snippets:
public static ArrayList<String> permute(String begin, String end) {
ArrayList<String> al=new ArrayList<String>();
//filling bla
return al;
}
and here's where I call the function in the main function:
ArrayList<String> arr =permute("","abc");
arr unfortunately is empty, and I have no idea how to get it to work :(
Thanks in advance
EDIT:
Here's the full code:
import java.util.*;
class Problem24 {
public static ArrayList<String> permute(String begin, String end) {
ArrayList<String> al=new ArrayList<String>();
if (end.length() <= 1) {
String s=begin+end;
al.add(s);
} else {
for (int i = 0; i < end.length(); i++) {
try {
String newString = end.substring(0, i) + end.substring(i + 1);
permute(begin + end.charAt(i), newString);
} catch (StringIndexOutOfBoundsException exception) {
exception.printStackTrace();
}
}
}
return al;
}
public static void main (String[] args)
{
ArrayList<String> arr =permute("","abc");
System.out.println(arr.get(0));
}
}
Your ArrayList is empty but not null which means that the returning part worked. In oder to use the values from the method you need to fill the ArrayList inside the method.
ps: You should use List list = new ArrayList() or
List list = permute("", "abc") which is a simple version of dependency injection and a better design of your program.
You're not adding the items from the recursive calls.
Try adding the al.addAll to your permute call:
al.addAll(permute(begin + end.charAt(i), newString));
before returning the value make sure you are filling the al List
al.add(begin);
al.add(end);
al.add("any other string");
return al;
Obviously something in wrong with the // filling bla part.
I'd start with replacing your code in // filling bla with al.add("TEST"); and see if you even get something out.
Also your method is static and the source array isn't passed in, which suggest that either your code is supposed to permute those strings somehow. Are you possibly acting upon a static array (i.e. permute all elements between begin and end), and the source array is empty?
import java.util.*;
class Problem24
{
public static ArrayList<String> permute(String begin, String end)
{
ArrayList<String> al=new ArrayList<String>();
if (endingString.length() <= 1)
{
String s=begin+end;
al.add(s);
}
else
{
for (int i = 0; i < end.length(); i++)
{
try
{
String newString = end.substring(0, i) + end.substring(i + 1);
al.add(permute(begin + end.charAt(i), newString));
}
catch (StringIndexOutOfBoundsException exception)
{
exception.printStackTrace();
}
}
}
return al;
}
public static void main (String[] args)
{
ArrayList<String> arr = permute("","abc");
System.out.println(arr.get(0));
}
}
hope i corrected it the right way.
You call your method permute recurrently --- but you make no use of what it returns when it returns. In other words, you create a new array each time you call permute, but everything you get in for-loop is lost, as you are not passing it to next permute() calls --- eventually you return an empty array in which you didn't put anything.

Java, getter for array values (array dynamically defined)

I have a series of String[] arrays which are list of words. Something like:
String[] ListOne = new String[100];
String[] ListTwo = new String[100];
/*And so on with other lists */
ListOne[0] = "word00";
ListOne[1] = "word01";
/*And so on till*/
ListLast[99] = "word 99 from last list";
Now I want a function for each list that, given a number returns the corresponding element (word):
public String GetFromListOne(int key) { return ListOne[key];}
Is there a way to avoid manually writing each of this getter functions?
In PHP, for example, I would just use the magic method __call,
or pass as an argument with the list name and reference it dynamically.
Is there a way to do something similar in Java?
Or an alternative strategy to achieve the same result?
You should look into inheritance.
What you basically must do is define an interface (or extend a List class)
public interface ListTest{
//**Gets keys from lists*//
GetFromListOne(int key);
}
then
public class Listone implements ListTest{
/** methods **//
GetFromListOne(int key);
/** methods **//
}
Have fun extending
http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html
You could use a 2 dimensional array, or a list of arrays and have your function take 2 parameters. One for the array that you want and the other for the element in the array.
2 dimensional array:
String[][] ListN = new String[100,100];
String getFromList(int n, int key) {
return ListN[n][key];
}
Or list of arrays:
List<String[]> listOfArrays = new ArrayList<String[]>();
listOfArrays.add(new String[100]);
listOfArrays.add(new String[100]);
String getFromList(int n, int key) {
return listOfArrays.get(n)[key];
}
Could you have a function that takes as input the key and the list number:
public String GetFromListOne(int list, int key) {
switch(list):
case 1:
return ListOne[key];
break;
case 2:
return ListTwo[key];
break;
...
}
or even better make an array of arrays:
String[][] ListOfLists = new String[10];
ListOfLists[0] = new String[100];
...
public String GetFromList(int list, int key) {
return ListOfLists[list][key];
}
Otherwise I don't know of a function to override like __call
String[] ListFour=new String[100];
String[] ListTwentyThree=new String[100];
String[] ListNine=new String[100];
String[] ListOne=new String[100];
Hashtable<Integer,String[]> yourlist=new Hashtable<Integer,String[]>();
yourlist.put(4, ListFour);
yourlist.put(23, ListTwentyThree);
yourlist.put(9, ListNine);
yourlist.put(1, ListOne);
System.out.println(yourlist.get(4)[5]);//fifth string in ListFour
System.out.println(yourlist.get(23)[51]);//fifty first string in List23
System.out.println(yourlist.get(9)[1]);//first stringin ListNine
another version:
Hashtable<Object,String[]> yourlist=new Hashtable<Object,String[]>();
yourlist.put("two multiplied by two", ListFour);
yourlist.put(23, ListTwentyThree);
yourlist.put(0.03, ListNine);
yourlist.put(true, ListOne);
System.out.println(yourlist.get("two multiplied by two")[5]);//fifth string in ListFour
System.out.println(yourlist.get(23)[51]);//fifty first string in List23
System.out.println(yourlist.get(true)[1]);//first stringin ListNine
Based in the __call PHP method, you can achieve this implementing a method that receives the list and the index, and using generics you can get something like this.
public class Utility {
public <T> T getElementFromArray(T[] array, int index) {
if (index >= array.length || index < 0) return null;
return array[index];
}
}
The pitfall of this method is that can't be used for primitive array holders, like int[]. The solution for these cases would be using the wrapper classes for primitive types.
public static void main(String[] args) {
Utility u = new Utility();
String[] ss = new String[2];
ss[0] = "Hello";
ss[1] = "world!";
System.out.println(u.getElementFromArray(ss, 0));
System.out.println(u.getElementFromArray(ss, 1));
int[] ii = new int[2];
ii[0] = 5;
System.out.println(u.getElementFromArray(ii, 0)); //compile error
//Solution: use wrapper classes
Integer[] ii2 = new Integer[2];
ii2[0] = 5;
System.out.println(u.getElementFromArray(ii2, 0));
}
Try this code
List<String[]> lists = new ArrayList<String[]>();
public String getFromLists(int key) {
List<String> res = new ArrayList<String>();
for (String[] s: lists){
res.add(s[key]);
}
return res.get(key);
}
or better
public String getFromLists(int key) {
return lists.get(key)[key];
}

Categories

Resources