compare two arraylist object not working - java

I have two array list with name list and sum from this kind of class :
public class Factor {
private String cat;
private String kind;
private String name;
private int number;
private String id;
}
my purpose is compare this two arraylist and if they have same object , list number = sum number else sum object add to list .
this is my try so far :
int size=list.size();
for (int j=0; j<size ;j++){
for (int i = 0; i < sum.size(); i++) {
if (list.get(j).getId().equals(sum.get(i).getId())){
list.get(i).setNumber(sum.get(i).getNumber());
} else {
list.add(new Factor(sum.get(i).getId(),sum.get(i).getCat(),sum.get(i).getKind(), sum.get(i).getName(), sum.get(i).getNumber()));
}
}
}
but problem is always two condition run any way it mean do below in if list.get(i).setNumber(sum.get(i).getNumber());
and after that do below in else
list.add(new Factor(sum.get(i).getId(),sum.get(i).getCat(), sum.get(i).getKind(),
sum.get(i).getName(), sum.get(i).getNumber()));
always add list ... so where am i wrong ?

Your logic was incorrect.
Based on the comments, you want to add to list all the elements of sum that don't have a matching ID in list. For that purpose you should iterate over the elements of sum first (i.e. in the outer loop).
int size=list.size();
for (int i = 0; i < sum.size(); i++) {
boolean found = false;
for (int j=0; j<size ;j++) {
if (list.get(j).getId().equals(sum.get(i).getId())) {
list.get(j).setNumber(sum.get(i).getNumber());
found = true;
break;
}
}
if (!found) {
list.add(new Factor(sum.get(i).getId(),sum.get(i).getCat(), sum.get(i).getKind(),
sum.get(i).getName(), sum.get(i).getNumber()));
}
}

you need to make sure both list size is the same, so if they are not the same size they wont be equal
Also this is a bad practice to compare two lists, a better way would be using a Set, just convert one of the lists to a set ( time complexity O(n) ) then loop over the other list and check if all elements are in the set you created from the other list, also you need to take care of duplicate case , so if duplicate is allowed in the list you need to use a map , where the id is the key and the value is the number of occurrences , while iterating over the other list if the key is found decrement the number and check if its not getting less than zero.

From your question, it's still not clear what you are trying to achieve from this code. Do you wanna compare every element of list array with every element of sum array or u just want to compare list array with the corresponding element of sum array.
As per my understanding,
From your code, I can see that u are using nested loos.
***for (int j=0; j<size ;j++)
{
for (int i = 0; i < sum.size(); i++) {}}***
So for every list(j) array, it will compare this all the elements of sum(i) array and out which some will execute IF block and some will execute else block depending upon the condition.
If this is not what u are looking for they give some more clarity on ur question.

Related

How would you make a function with a while and for loop to return the last item in a list?

Say I had a method finalNum() where I want to use this method to pick out the final number in a list i.e. {1,2,10,12} and returns 12
What is the simplest way to do so using a for loop vs a while loop? Can someone show both? I'm new to code and trying to find a simple example.
Since Lists are based on arrays which are zero-indexed, the last element is the element at index list.size() - 1. Using List#get will suffice; there is no need for looping at all.
final List<Integer> list = List.of(1,2,10,12);
final Integer last = list.get(list.size() - 1);//12
If you really want to solve this question for educating purposes, you can take a look at these examples.
Here we loop from the beginning to the end and saving each element of the list to a variable. After we have finished looping we return the value which is by definition the last element of the list
static int finalNum(List<Integer> listOfNumbers) {
int result = 0;
for (int i = 0 ; i < listOfNumbers.length(); ++i) {
result = listOfNumbers.get(i);
}
return result;
}
You can do it the other way around, too:
static int finalNum(List<Integer> listOfNumbers) {
int result = 0;
for (int i = listOfNumbers.length() - 1; i >= 0; --i) {
return listOfNumbers.get(i);
}
throw new IllegalStateException("list contains no elements");
}
That loop goes from the end to the beginning. So the loop does not actually loop. This is mostly not what the developer wants or has intended.
The first example as a while loop
static int finalNum(List<Integer> listOfNumbers) {
int result = 0;
Iterator<Integer> iterator = listOfNumbers.iterator();
while(iterator.hasNext())
result = iterator.next();
}
return result;
}
Here we also loop from the beginning to the end storing everything in a variable which we return as result at the very end.
But after all, none of this is recommend as you can easily access the last element of a list via list.get(list.size() - 1). The above code is by no means code for production.

Could we remove while iterating if we just remove 1 element?

I have a list of custom objects. I need to get/remove a specific object from that list but the equals implemented would not work based on what I need to search.
The following would work:
int index = -1;
for(int i = 0; i < list.size(); i++) {
if(list.get(i).getAttr().equals(arg)) {
index = i;
break;
}
}
CustomObject = list.remove(index);
// use CustomObject here
I was wondering if I could do the list.remove inside the for loop despite not using an iterator since the loop breaks immediately
Using the delete(int) method in your loop will work just fine.
Your loop is closed so you have full control on i and you can use the list as you please. You don't use i after having deleted the first element that matches, so there are no caveat. If you were to reuse it, you would have to not increment it.
To avoid any trouble, the following if both more readable and expressive. Also, it's totally implementation-agnostic.
CustomObject deletedObject = null;
for (Iterator<CustomObject> i = list.iterator(); i.hasNext(); ) {
CustomObject candidate = i.next();
if (candidate.getAttr().equals(arg)) {
deletedObject = candidate;
i.remove();
break;
}
}
if (deletedObject != null) {
// Do something with deletedObject
}
There is no special program state associated with “being inside a for loop”. What matters, are the actions your program performs.
So
int index = -1;
for(int i = 0; i < list.size(); i++) {
if(list.get(i).getAttr().equals(arg)) {
index = i;
break;
}
}
CustomObject o = list.remove(index);
// use CustomObject here
is identical to
for(int i = 0; i < list.size(); i++) {
if(list.get(i).getAttr().equals(arg)) {
CustomObject o = list.remove(i);
// use CustomObject here
break;
}
}
as it performs the same actions (letting aside that the first variant will throw when no match has been found). The differences regarding local variables defined in these code snippets are, well, local and do not affect anything outside the containing method.
That said, the rule that you must not modify a collection (except through the iterator) while iterating over it, applies to iterator-based loops, where you are not in control of the iterator’s internal state. When you are using an index based loop and fully understand the implications of removing an object at a particular index (of a random access list), you can even continue iterating. The important aspects, to do it correctly, are that the indices of all subsequent elements decrease by one when removing an element, further the size decreases so you must either, reread the size or decrement a previously cached size value.
E.g., the following loop is valid
for(int i = 0; i < list.size(); i++) {// rereads size on each iteration
if(list.get(i).getAttr().equals(arg)) {
CustomObject o = list.remove(i--); // decrease index after removal
// use CustomObject here
// continue
}
}
But, of course, it’s more idiomatic to use an Iterator or removeIf, as these approaches are not only easier to handle, they also work with other collections than random access lists. And especially removeIf may be more efficient when you remove more than one element.
Just another way using streams,
List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("D");
str1.add("D");
Optional<Object> foundVal = str1.stream().filter(s ->
s.contains("D")).findFirst().map(val -> {
str1.remove(val);
return val;
});
System.out.println(str1);
System.out.print(" " + foundVal.get());
Output
[A, B, D] D

Removing duplicates from an ArrayList?

Good afternoon everyone, I am currently studying for my Java Final and I have a review exercise that asks the reader to create a program that asks the user to input 10 integers and then to use a method to remove duplicates and display the distinct list. The method is provided for you as well.
I've gotten the majority of the code written, in fact I thought I was done until I realized that the for loop is removing more than just duplicates..
Here is my code:
public class lab25 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int i;
//Create array list
ArrayList<Integer> numbers = new ArrayList<>();
System.out.println("Please enter 10 numbers!");
//Populate
for(i=0; i<10; i++) {
numbers.add(input.nextInt());
}
System.out.println("Your numbers are: " + numbers.toString());
removeDuplicate(numbers);
System.out.println("The distinct numbers are: " +numbers.toString());
input.close();
}
public static void removeDuplicate(ArrayList<Integer> list) {
int i;
for(i=0; i<list.size(); i++) {
if(list.contains(list.get(i))) {
list.remove(i);
}
}
}
}
Just curious what I have done wrong here? I think my issue might lie in my for loop.. Thanks to all who answer.
list.contains(list.get(i)) always returns true, since the i'th element of the List is contained in the List.
Therefore removeDuplicate is trying to remove all the elements (but you only remove half of them, since after removing the i'th element you skip the new i'th element).
There are many ways to remove duplicates. The most efficient involve using a HashSet. If you want to find duplicates using only List methods, you can check if list.lastIndexOf(list.get(i)) > i.
The expression list.contains(list.get(i)) is always true, since you're asking if the list contains some element from the list. You need to check if list.get(i) is contained in the first i-1 items in the list, which I recommend doing with a loop.
Be aware that a loop with list.remove will run slowly, since removing item i from an ArrayList is done by replacing item i with i+1, then replacing item i+1 with i+2 and so on. This means it takes around length^2 time to make a loop that calls remove in every iteration. The function list.contains has the same problem, as it has to go through the entire list. This may not matter if you have 10 items, but if you had a list with a million items, it would take a long time to run.
The easiest ways is to use Stream.distinct():
public static List<Integer> removeDuplicate(List<Integer> list) {
return list.stream().distinct().collect(Collectors.toList());
}
In case you are free to choose collection, you should use LinkedHashSet instead. It holds ordered unique numbers.
A solution could be this one. I startet at the end of the list that I don't delete indexes the loop has to visit in the future.
public static void removeDuplicate(ArrayList<Integer> list) {
int i = list.size() - 1;
while (i > -1) {
// check for duplicate
for (int j = 0; j < i; j++) {
if (list.get(i) == list.get(j)) {
// is duplicate: remove
list.remove(i);
break;
}
}
i--;
}
}
You are taking the list.get(i) which of course is present in the list, and you will delete all of the values in the end.
You could remove them by using a set:
Set<String> hs = new HashSet<>();
hs.addAll(numbers);
numbers.clear();
numbers.addAll(hs);
If you want to keep the current order and do not want to use set.
List<String> notduplicatedList =
new ArrayList<>(new LinkedHashSet<>(String));

get element from ArrayList (java)

Struggling with what is probably a simple query to match and return an element in an ArrayList.
I first store a HashSet in the ArrayList because HashSet has no get method and then check the ArrayList (which contains the correct elements, strings of socket references).
List theseSocks = new ArrayList(NodeConnMaster.sockList);
System.out.println("array list contains " + theseSocks);
I then want to iterate through and find the matching ipAddress in the element and once found set a variable to the entire element, so something like -
for (int i =0; i< theseSocks.size(); i++) {
if (theseSocks.toString().contains(ipAddress)) {
int element = theseSocks.get();
System.out.println("the element is " + element);
}
}
but it appears that get needs an index position and I am trying to get based on string contents, not index.
Is there an easier way than deleting all the elements except the matching one and then returning index 0.
Or is ArrayList not the way to go.
The solution was, with SBylemans's help -
Object currentSock = null;
for (int i =0; i< theseSocks.size(); i++)
{
currentSock = theseSocks.get(i);
if (currentSock.toString().contains(ipAddress))
{
System.out.println("the element is " +currentSock);
break;
}
}
Regards
Ralph
You can use stream of Java8 for filtering required elements like:
List wantedList = theseSocks.stream()
.filter(e ->e.toString().contains(ipAddress))
.collect(Collectors.toList())
You're looping over the ArrayList and want to compare based on the String value. But looping like this will immediately also give you the index. Your loop should look something like this:
for (int i =0; i< theseSocks.size(); i++)
{
String currentSock = theseSocks.get(i);
if (currentSock.equals(ipAddress))
{
System.out.println("the element is " +currentSock);
break;
}
}
Or even with a forEach loop
for (String currentSock: theseSocks)
{
if (currentSock.equals(ipAddress))
{
System.out.println("the element is " +currentSock);
break;
}
}
The break is used to interupt the for loop once your element is found.
Additionaly, your if condition will cause a print of every element if the array contains the ipAddress you're looking for.
Edit And then when using java 8, you can also use streams as posted by others.

get value that occurs more than one in a list?

What are the the best methods to get values that occur more than once in a large list of words without slowing my run time?. My file contains 1xx,xxx words and I put them into a linked list. Now, I want to get only the words that occur more than once out of that list.
For example, if a list contains:
....This is is is just a test test....
I want to get is and test and put them into another list using an iterator.
I don't know if my code is right, and I think that this is not the best solution to approach for this problem.
for(int i = 0; i < word.size(); i++) {
Word s = word.get(i);
Word s1 = word.get(i+1);
if(s.equals(s1)) {
newWord.add(s);
}
}
Put them all into HashSet instead of list and check the return value of add() method.
HashSet<Word> wordSet = new HashSet<>();
for(int i = 0; i < word.size(); i++) {
if(!wordSet.add(word.get(i)){
//Found duplicate
}
}
Note that you can also do it during/instead of creation of the list of the words.
Build a hashmap with the word as key and it count as value.
for(each word in list)
{
count = 1;
if(map.contains(word))
{
count = map.get(word);
}
else
count = 1;
map.put(word,count);
}
Then iterate over the hashmap and check if values is 1, and add the word to your list.
If you can sort the list, then finding duplicates is quick and easy.

Categories