I have two ArrayLists of the same model class (i.e ListA and ListB) to which I have added the same data.
Then I added some data only in the second arraylist ListB.
Now, I want to fetch only that data which is different in both ListA and ListB and store the result in a third arraylist ListC.
I tried below code. However, all elements are stored in ListC, as opposed to only those that are different:
ArrayList<C> ListC = new ArrayList<>();
for (int i = 0; i < ListA.size(); i++) {
for (int j = 0; j < ListB.size(); j++) {
if (ListA.get(i).getName() == ListB.get(j).getName()) {
Log.e("Do", "Nothing");
} else {
C c = new C(b.get(j).getName());
ListC.add(c);
}
}
}
Edited Question
ArrayList<Model> a = new ArrayList<>();
Model model = new Model();
model.setName("MaHi");
model.setAge("20");
a.add(model);
ArrayList<Model> b = new ArrayList<>();
Model model = new Model();
model.setName("MaHi");
model.setAge("20");
b.add(model);
Model model2 = new Model();
model2.setName("Ritu");
model2.setAge("21");
b.add(model2);
ArrayList<Model> c=new ArrayList<>();
now I want to fetch that data which is not in either arraylist a or arraylist b (i.e. data of model2) into arraylist of c;
The problem is that you are iterating over all combinations.
Lets say A = [1, 2, 3] and B = [1, 3, 4].
Then, your loop would compare
a=1 with b=1. Both are equal, nothing is done. That's good.
a=1 with b=3. They are not equal, so 3 is added to C. Here is your first problem: 3 actually is in A, but just not in your current iteration.
a=1 with b=4. They are not equal, so 4 is added to C. In this case, this is okay, since 4 is not in A.
a=2 with b=1. They are not equal, so 1 is added to C. However, 1 is actually in A.
and so on
Do you see how your solution does not work? You cannot compare every combination. Instead, you have to check for every element in B, if it is in A. If no, add.
This, directly translated to pseudo code, looks like
// for every element in ListB
for (int i = 0; i < ListB.length(); i++) {
B b = ListB.get(i);
// if this is not in ListA
if (!ListA.contains(b))
ListC.add(b);
}
However, here you should use the for-each loop for (B b: ListB).
And even better, simply use ListC.addAll(ListB); ListB.removeAll(ListA).
(And make sure hashCode and equals are properly written - but that is a different issue.)
Of course, this requires that the Elements in ListA and ListB are of the same type. See Jekin's answer for a solution using less standard library methods that also works with different types (as long as both implement getName(), of course).
This also resolves a second issue, as stated in the comments on your question: You cannot compare Strings with ==, but have to use the equals method. Try x = new String("a"); y = new String("a"); assert(x==y); and assert(x.equals(y));
As you have different class model(A,B) for all list, contains and remove methods might not be helpful for you, so you can use a flag contained like this:
Arraylist<C> ListC = new ArrayList<>();
for (int i = 0; i < ListB.size(); i++) {
// initially, assume that this element is not contained in ListA
boolean contained = false;
// check if this element is contained in ListA
for (int j = 0; j < ListA.size(); j++) {
if (ListA.get(i).getName().equals(ListB.get(j).getName())) {
contained = true;
}
}
// if this element is not contained once in ListA,
if (!contained) {
// add it to ListC
C c = new C();
c.setName(b.get(j).getName());
ListC.add(c);
}
}
This flag indicates, for every element in ListB, if it is contained at least once in ListA.
This ensures that each element in ListB is added at most once—your loop could add each element multiple times.
The problem is here in your code
if (ListA.get(i).getName() == ListB.get(j).getName()) {
Log.e("Do", "Nothing");
} else {
C c = new C();
c.setName(b.get(j).getName());
ListC.add(c);
}
You are using == operator to compare String values. Which is used for reference comparison not value comparison. While this may produce accurate results in many different programming languages but Java handles value comparisons differently. You need to use equals() or equalsIgnoreCase method instead of ==.
So change the line to
if (ListA.get(i).getName().equals(ListB.get(j).getName()))
Note : An == operator can sometimes produce correct results but only because the different Strings' references share the same object not because they have the same value.
Try below code
Arraylist<C> ListC = new ArrayList<>();
for (int i = 0; i < ListA.size(); i++) {
for (int j = 0; j < ListB.size(); j++) {
if (ListA.get(i).getName().equals(ListB.get(j).getName())) {
Log.e("Do", "Nothing");
} else {
C c = new C();
c.setName(b.get(j).getName());
ListC.add(c);
}
}
}
Just let me know if it doesn't resolve your need
i will definitely help you
public static void main(String arg[])
{
ArrayList<String> a=new ArrayList<>();
a.add("hello");
a.add("hi");
a.add("stack");
a.add("overflow");
a.add("empty");
a.add("world1");
ArrayList<String> b=new ArrayList<>();
b.add("hello");
b.add("hi");
b.add("stack");
b.add("overflow");
b.add("empty");
b.add("world");
ArrayList<String> c=new ArrayList<>();
int flag=0;
System.out.println(a.contains("empty"));
for (int i = 0; i < a.size(); i++) {
if(b.contains(a.get(i)))
{
}
else
{
System.out.println("haii");
c.add(a.get(i));
}
}
System.out.println(c.toString());
}
you try this example
Related
I am trying to get pass a coding challenge. The goal is to remove duplicate (after a defined 'n-th' time) from the array.
For example,
int[] arr;
arr = new int[] {1, 2, 2, 3, 3, 3, 4, 5, 5};
arr = tester(arr,1);//return 1,4. anything having more then 1 occurrence is removed from the //array
I have 2 questions here.
I understand that although java is mainly call by value,
more detail: https://stackoverflow.com/questions/12757841/are-arrays-passed-by-value-or-passed-by-reference-in-java#:~:text=Longer%20answer%3A,object%20that%20the%20caller%20sees.
and
Is Java "pass-by-reference" or "pass-by-value"?
.
so am I not able to modify/return the value of arr without re-assigning it as I need to use the "new" keyword later on.
example:
I am not able to do the following:
tester(arr,1) //return the original value, as the method has a "new" when converting the
//arraylist into array. There seems to be no work around for this as well..
I am also only passing 2 out of 10 test case in the coding challenge, I am not very sure why. I have also attempted to error handle with string inputs, or length=0 or null, to no success. (or implemented it in hashmap for sake of time complexity)
It does not seem like my logic has an issue, I am just not sure what are the test case as it is hidden.
I believe part of the challenge requires me to return it in the original array, meaning changing the value of arr itself, but i cant find a way to do it without using the new keyword.
Any ideas anyone?
public static int[] tester(int[] data, int n)
{
ArrayList<Integer> storeNon_dup = new ArrayList<Integer>();
//nested for loop to run through the array
//store in arrayList if criteria valid
for(int i = 0; i < data.length; i++)
{
int counter = 0;
for(int j = 0; j< data.length; j++)
{
if(data[i] == data[j])
{
counter++;
}
}
//if not duplicate in n-th occurence, add to list
if(counter<=n)
{
storeNon_dup.add(data[i]);
}
}
//convert arraylist to array
int[] container = new int[storeNon_dup.size()];
for(int i = 0; i<storeNon_dup.size(); i++)
{
container[i] = storeNon_dup.get(i);
}
return container;
}
Alternate solution by using HashMap.
public static List tester(int[] data, int n) {
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i=0; i<data.length; i++) {
if(map.containsKey(data[i])) {
map.put(data[i], map.get(data[i])+1);
}else {
map.put(data[i], 1);
}
}
List lst = new ArrayList<Integer>();
for(Integer key : map.keySet()) {
if(map.get(key)<=n) {
lst.add(key);
}
}
return lst;
}
I am using below program to find the subsequences in an given given list. When I am using clear() , the values in li is also getting cleared. Hence, I am creating a new reference everytime.
I wanted to understand the logic behind this. Am I using it wrong? Or it is the reference that I am adding to my li?
public static int getTheSubseq(List<Integer> AList){
// int[][] subsequences = new int[][];
List<List<Integer>> li = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
for (int i = 0; i < AList.size(); i++){
for(int j =i+1; j < AList.size(); j++){
temp.add(AList.get(i));
temp.add(AList.get(j));
li.add(temp);
temp = new ArrayList<>();
//temp.clear();
}
}
System.out.println(li);
return 1;
}
Regardless of whether or not you are calling temp.clear(), if you add to li multiple times a reference to the same List object, li will contain multiple references to the same List object, which means li.get(0) == li.get(1), li.get(0) == li.get(2), and so on...
Making changes in one of these inner Lists will be reflected in all the other inner Lists, since there's just one List referenced multiple times.
Therefore, assigning a new ArrayList instance to temp in each iteration of your loop (before adding it to li) is the right thing to do.
I'd make a slight change though - create the new inner List just before adding it to the outer List:
for (int i = 0; i < AList.size(); i++){
for(int j =i+1; j < AList.size(); j++){
List<Integer> temp = new ArrayList<>();
temp.add(AList.get(i));
temp.add(AList.get(j));
li.add(temp);
}
}
Adding the element to li doesn't make a copy. So when you call clear() you'll have both temp and an element inside li that point to the same object.
You may want to just declare temp inside the inner loop, so you get a fresh one every time without needing to call clear().
When you call .clear() (or any other method for that matter), you're operating on the same refernece.
Here, if you don't create a new list each iteration, you're adding the list referenced to by temp to li. When you call clear(), they are "all" cleared, since they all point to the same object.
When you create a new list each iteration, you have different objects, and can operate on them independently.
Try doing this:
public static int getTheSubseq(List<Integer> AList){
// int[][] subsequences = new int[][];
List<List<Integer>> li = new ArrayList<>();
List<Integer> temp;
for (int i = 0; i < AList.size(); i++){
for(int j =i+1; j < AList.size(); j++){
temp = new ArrayList<>();
temp.add(AList.get(i));
temp.add(AList.get(j));
li.add(temp);
}
}
System.out.println(li);
return 1;
}
ArrayList<Integer> co = new ArrayList<Integer>();
ArrayList<Integer> gu = new ArrayList<Integer>();
System.out.println(code.size());
System.out.println(guess1.size());
for(int b = 0; b < code.size(); b++) {
for (int i = 0; i < guess1.size(); i++){
if(guess1.get(i).equals(code.get(b)) && (i == b) && ((Arrays.asList(co).contains((b))))&&(!(Arrays.asList(gu).contains(i)))){
co.add(b);
gu.add(i);
hintboard.add(Hints.B);`enter code here`
System.out.println(guess1);
System.out.println(co);
System.out.println(gu);
}else if(guess1.get(i).equals(code.get(b)) && (!(Arrays.asList(co).contains((b))))&&(!(Arrays.asList(gu).contains(i)))){
co.add(b);
gu.add(i);
hintboard.add(Hints.W);
//System.out.println(hintboard);
What I am trying to do here is that, check if i is equal to b at the same position and make sure the index is not present in arrayList of co and gu. however the statement is true every time even though the first index of b is added in co and the index of i is added to gu.
Im not sure if i understood your whole problem, but here it goes anyways:
Your problem is that you use:
Arrays.asList(co).contains((b))
First of all the parentheses around b is unnecessary/useless so you should remove them.
And the reason it doesnt work is that Arrays.asList will create a list with all the elements passed into it. The intended use would be something like this:
Arrays.asList(1, 2, 3);
Which will return the list:
[1, 2, 3]
Your code puts a list in to a list so the output would be something like this:
[[YOUR, LIST, ITEMS]]
and your code of Arrays.asList(co).contains((b)) will do a test similar to this psudo-code:
[[1, 2, 3]].contains(2)
This will always return false since the main list does not contain 2 it only contains a sublist [1, 2, 3] It would work if you did this Arrays.asList(co).get(0).contains((b)) as .get(0) would return the first sublist, but this only correct a mistake you created, so the correct way to write the line in the first place would be:
co.contains(b)
I can not tell you if your code works as a whole, after this fix, as there is many ways to play mastermind, and i am not sure of the rules you play by. Also I do not fully understand the full process of your code, only the concept. Anyways here is your corrected code (Hope this helped you understand):
ArrayList<Integer> co = new ArrayList<Integer>();
ArrayList<Integer> gu = new ArrayList<Integer>();
System.out.println(code.size());
System.out.println(guess1.size());
for(int b = 0; b < code.size(); b++) {
for (int i = 0; i < guess1.size(); i++) {
if (guess1.get(i).equals(code.get(b)) && (i == b) && co.contains(b) && !gu.contains(i)) {
co.add(b);
gu.add(i);
hintboard.add(Hints.B);
System.out.println(guess1);
System.out.println(co);
System.out.println(gu);
} else if (guess1.get(i).equals(code.get(b)) && !co.contains(b) && !gu.contains(i)) {
co.add(b);
gu.add(i);
hintboard.add(Hints.W);
//System.out.println(hintboard);
}
}
}
the following code does the following: for each element in 'a', find if it has match in element 'b':
String a[] = new String[]{"a","b","c"};
String b[] = new String[]{"e","f","a","a"};
String hold="";
for (int i = 0; i < a.length; i++){
for (int k = 0; k < b.length; k++){
if ( a[i].equals( b[k]) ){
hold+=a[i];
}//if
}//for
}//for
the problem is that sometimes array 'b' can contain duplicates, but we do not want
duplicates to be recorded in the variable 'hold'
Here is what i have tried - save all matches to a HashSet, then use the containsKey() to first
check it is in the hashset, if not, then update the 'hold' variable. Have also tried to record each match in an array and first check this array before updating the 'hold' variable
Is there another way to do this? Is there a more optimal way to do this?
Add a break so you leave the for as soon as you get an object that matches
for (int k = 0; k < b.length; k++){
if ( a[i].equals( b[k]) ){
hold+=a[i];
break;
}//if
}//for
EDIT:
If you want to stop the other for too do it like this:
start:
for (int i = 0; i < a.length; i++){
for (int k = 0; k < b.length; k++){
if ( a[i].equals( b[k]) ){
hold+=a[i];
break start;
}//if
}//for
}//for
EDIT
If you want to make sure you don't get the "a" duplicates do this:
String a[] = new String[]{"a", "b", "c"};
String b[] = new String[]{"e", "f", "a", "a"};
List<String> matches = new ArrayList<String>();
String hold = "";
for (String anA : a)
if (!matches.contains(anA))
for (String aB : b)
if (anA.equals(aB))
{
hold += anA;
matches.add(anA);
}//if
}//for
}//for
You should consider using a Set for your hold variable so that it doesn't contain duplicates, and use the retainAll method to get the intersection between a set and another collection (which can contain duplicates).
Using a sets would automatically remove duplicates.
Set< String > mySet1 = new HashSet< String >(Arrays.asList(a));
Set< String > mySet2 = new HashSet< String >(Arrays.asList(b));
mySet1 or mySet2 would not contain any duplicates.
According to your example mySet1 would be {"a","b","c"} and mySet2 would be {"e","f","a"}
After this point you can use multiple methods to get where you want check this documentation.
I believe you are looking for removeAll function.
I would convert them to a List and use retainAll to find the matches. Then just loop the list for your hold var. You don't have to worry about duplicates in b using this method. retainAll will not care that it is in b twice. It will retain a because it existed in b. Whatever is left in the a Array will get concatenated into your hold.
String a[] = new String[]{"a","b","c"};
String b[] = new String[]{"e","f","a","a"};
//get new ArrayList because asList is immutable
List<String> aList = new ArrayList(Collections.asList(a));
List<String bList = Collections.asList(b);
aList.retainAll(bList);
StringBuilder sb = new StringBuilder();
for(String s : aList) {
sb.append(s);
}
String hold = sb.toString();
using java.util.List is easy:
List<String> listB = new LinkedList();
for(int i = 0; i < b.lenght; i++) listB.add(b[i]);
for(int i = 0; i < a.lenght; i++) {
if(listB.contains(a[i])) hold+=a[i];
}
Well, what i see you are doing, is you have 2 arrays with content in it. I understand the content is going to be different in the future. Every time you iterate through 1 character of array A, you want to test if array B has a equal value. If so you want to store that value ONCE in the array/string Hold.
Why not just check in hold if the value already exists, and if not, add it, if so, skip it?
PS: Sorry I did not do this in the comments, but I do not have enough rep to comment on the issue itself.
I have these three collections in Java:
ArrayList<Integer> list1 = new ArrayList<Integer>(6000);
ArrayList<Integer> list2 = new ArrayList<Integer>(6000);
ArrayList<Integer> list3 = new ArrayList<Integer>(6000);
Which is more efficient to loop through and set to 0?
for(int i =0; i < rHist.size(); i++) {
list1.set[i] = 0;
list2.set[i] = 0;
list3.set[i] = 0;
}
Or this?
for (int n : list1) {
n = 0;
}
for (int n : list2) {
n = 0;
}
for (int n : list3) {
n = 0;
}
Thanks
As already mentioned in the comments, both of the variants do not reach the goal you stated. That being said, better look to write readable, understandable and short code and refrain to the methods given in the Collections API. Something like that fills your list with 6000 copies of zeros:
List<Integer> list = Collections.nCopies(6000, 0);
If you need to mutate the list afterwards, you need to wrap it in a modifiable List like so:
List<Integer> list = new ArrayList<Integer>(Collections.nCopies(6000, 0));
The first one is better because you are looping one time instead of three if you put the size to 6000 in the loop, and the set should look like this list1.set(i,0) instead of list1[i]=0
if you decompiled both them uisng javap -c "appname" lets assume that they are under the main, you can see your self whats happening