How to add element in List while iterating in java? - java

Say I have a List like:
List<String> list = new ArrayList<>();
list.add("a");
list.add("h");
list.add("f");
list.add("s");
While iterating through this list I want to add an element at the end of the list. But I don't want to iterate through the newly added elements that is I want to iterate up to the initial size of the list.
for (String s : list)
/* Here I want to add new element if needed while iterating */
Can anybody suggest me how can I do this?

You can't use a foreach statement for that. The foreach is using internally an iterator:
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
(From ArrayList javadoc)
In the foreach statement you don't have access to the iterator's add method and in any case that's still not the type of add that you want because it does not append at the end. You'll need to traverse the list manually:
int listSize = list.size();
for(int i = 0; i < listSize; ++i)
list.add("whatever");
Note that this is only efficient for Lists that allow random access. You can check for this feature by checking whether the list implements the RandomAccess marker interface. An ArrayList has random access. A linked list does not.

Iterate through a copy of the list and add new elements to the original list.
for (String s : new ArrayList<String>(list))
{
list.add("u");
}
See
How to make a copy of ArrayList object which is type of List?

Just iterate the old-fashion way, because you need explicit index handling:
List myList = ...
...
int length = myList.size();
for(int i = 0; i < length; i++) {
String s = myList.get(i);
// add items here, if you want to
}

You could iterate on a copy (clone) of your original list:
List<String> copy = new ArrayList<String>(list);
for (String s : copy) {
// And if you have to add an element to the list, add it to the original one:
list.add("some element");
}
Note that it is not even possible to add a new element to a list while iterating on it, because it will result in a ConcurrentModificationException.

I do this by adding the elements to an new, empty tmp List, then adding the tmp list to the original list using addAll(). This prevents unnecessarily copying a large source list.
Imagine what happens when the OP's original list has a few million items in it; for a while you'll suck down twice the memory.
In addition to conserving resources, this technique also prevents us from having to resort to 80s-style for loops and using what are effectively array indexes which could be unattractive in some cases.

To help with this I created a function to make this more easy to achieve it.
public static <T> void forEachCurrent(List<T> list, Consumer<T> action) {
final int size = list.size();
for (int i = 0; i < size; i++) {
action.accept(list.get(i));
}
}
Example
List<String> l = new ArrayList<>();
l.add("1");
l.add("2");
l.add("3");
forEachCurrent(l, e -> {
l.add(e + "A");
l.add(e + "B");
l.add(e + "C");
});
l.forEach(System.out::println);

We can store the integer value while iterating in the list using for loop.
import java.util.*;
class ArrayListDemo{
public static void main(String args[]){
Scanner scanner = new Scanner(System.in);
List<Integer> list = new ArrayList<Integer>();
System.out.println("Enter the number of elements you wanna print :");
int n = scanner.nextInt();
System.out.println("Enter the elements :");
for(int i = 0; i < n; i++){
list.add(scanner.nextInt());
}
System.out.println("List's elements are : " + list);
/*Like this you can store string while iterating in java using forloop*/
List<String> list1 = new ArrayList<String>();
System.out.println("Enter the number of elements you wanna store or print : ");
int nString = scanner.nextInt();
System.out.println("Enter the elements : ");
for(int i = 0; i < nString; i++){
list1.add(scanner.next());
}
System.out.println("Names are : " + list1);
scanner.close();
}
}
Output:
Enter the number of elements you wanna print :
5
Enter the elements :
11
12
13
14
15
List's elements are : [11, 12, 13, 14, 15]
Enter the number of elements you wanna store or print :
5
Enter the elements :
apple
banana
mango
papaya
orange
Names are : [apple, banana, mango, papaya, orange]

Related

Best way to get unique list without changing the Order

I have a list of string or list of integers of 20,000 items
Now it contains duplicates...However i don't want to disturb the order of the item.
We can easily convert a list to Set for unique Set unique = new HashSet(list);
However the above breaks the sequential order of the items.
What would be the best approach for this?
Thanks.
You should use java.util.LinkedHashSet to get unique elements without changing the order:
Set<String> uniqueSet = new LinkedHashSet<>(list);
One other way is to use distinct():
list.stream().distinct().collect(Collectors.toList())
But distinct() uses LinkedHashSet internally. There is no need for unnecessary procedure.
So best way is using the LinkedHashSet constructor:
LinkedHashSet(Collection c) Constructs a new linked hash
set with the same elements as the specified collection.
You can try stream distinct
yourList.stream().distinct().collect(Collectors.toList());
Update1:
As I know, this is the best solution.
list.contains(element) will do 2 loop processes. One for iterate the element and add it to new list, one for check element is contained -> 0(n*n)
new LinkedHashSet() will created a new LinkedHashSet, and a new Arraylist output -> issue about memory. And the performance, i think it is equals with stream distinct
Update2: we must ensure that the output is a List, not a Set
As I know, stream distinct use HashSet internally. It is an more efficient memory implementation than LinkedHashSet (which is hash table and linked list implementation of the set interface) in our case.
Detail here
If you apply LinkedHashSet, the source code will something like below, so we have 1 ArrayList and 1 LinkedHashSet.
output = new ArrayList(new LinkedHashSet(yourList));
I did a small benchmark with 1k for-loop.
int size = 1000000;
Random rand = new Random((int) (System.currentTimeMillis() / 1000));
List<Integer> yourList = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
yourList.add(rand.nextInt(10000));
}
// test1: LinkedHashSet --> 35ms
new ArrayList<Integer>(new LinkedHashSet<Integer>(yourList));
// test2: Stream distinct --> 30ms
yourList.stream().distinct().collect(Collectors.toList());
If you don't want to break the order, then Iterate the list and make a new list as below.
ArrayList<Integer> newList = new ArrayList<Integer>();
for (Integer element : list) {
if (!newList.contains(element)) {
newList.add(element);
}
}
Try the bellow code
public static void main(String[] args) {
String list[] = {"9","1","1","9","2","7","2"};
List<String> unique = new ArrayList<>();
for(int i=0; i<list.length; i++) {
int count = unique.size();
if(count==0) {
unique.add(list[i]);
}else {
boolean available = false;
for(int j=0; j<count; j++) {
if(unique.get(j).equals(list[i])) {
available = true;
break;
}
}
if(!available) {
unique.add(list[i]);
}
}
}
//checking latest 'unique' value
for(int i=0; i<unique.size(); i++) {
System.out.println(unique.get(i));
}
}
It will return 9 1 2 7, but I haven't tried up to 20,000 collection lists, hopefully there are no performance issues
If you are trying to eliminate duplicates, you can use LinkedHashSet it will maintain the order.
if String
Set<String> dedupSet = new LinkedHashSet<>();
if Integer
Set<Integer> dedupSet = new LinkedHashSet<>();

Deleting specific object from ArrayList using for-loop

I am trying to delete one object from an ArrayList, but after iterating through the list with the for loop i'm stuck at what to do next. nameInput is a lowercase string from the user.
If i run this it prints the object from arr list equal to the input from nameInput. But I cannot understand how to go from printing that object to deleting it?
I'm sure this is a stupid question but the 50+ answers i have read and tried all seem to fail me (or more likely I fail to understand them). I have tried the list.remove and removeIf.
private ArrayList<Arr> arr = new ArrayList<>();
private void removeItem() {
for (Object arr : arr) {
if (((Arr) arr).getName().equals(nameInput())) {
System.out.println(arr);
break;
} else {
System.out.println("Error");
}
}
}
Using for loop
List<Arr> arr = new ArrayList<>();
for (Arr item : arr) {
if (item.getName().equals(nameInput())) {
arr.remove(item);
break;
}
}
If not call break after remove element, you get ConcurrentElementException
Note from #Aomine: you have to implement correct Arr.equals() method.
Using Iterator
List<Arr> arr = new ArrayList<>();
Iterator<Arr> it = arr.iterator();
while (it.hasNext()) {
Arr items = it.next();
if (item.getName().equals(nameInput())) {
it.remove();
break; // you can continue iterating and remove another item
}
}
Using Streams
List<Arr> arr = new ArrayList<>();
arr.removeIf(item -> item.getName().equals(nameInput()));
Remove all items that match given condition
This is not good to remove element from ArrayList. In case you know that you have to remove element from the middle of the List, do use LinkedList.
You are trying to remove an item while you are traversing/iterating the list in the for loop. You cannot remove an item from the list iterating it in a for loop. Use an Iterator instead and invoke arr.remove().
If you use Java 8 you could do
private void removeItem() {
arr.removeIf(t -> t.getName().equals(nameInput));
}
Note that this will remove all objects with name equal to nameInput
Also you should change your declaration of arr to
List<Arr> arr = new ArrayList<>();
A couple of things here...
The loop variable receiver type should ideally be Arr instead of Object as the list contains Arr objects. This also means you no longer need the cast you're performing.
You could remove the item via remove(Object o) but this requires overriding equals and hashcode based on name only. Another option is via an iterator but this would mean changing your code completely. Thus, to keep it as close to your code as possible you can use a for loop; get the index which the object is located and then remove.
Thus, you can do:
for(int i = 0; i < arr.size(); i++){
if (arr.get(i).getName().equals(nameInput)) {
Arr obj = arr.remove(i); // remove the item by index
System.out.println(obj); // print the object
break; // terminate the loop iteration
}
}

Need help useing a Iterator in java

I am trying to print out a array list of linked lists of size 8 using an Iterator here is what I have so far
ArrayList<LinkedList> myaol = new ArrayList<>();//my array which the linked lists are created when needed
public void printList(Iterator<Gen> itr)//gen is the generic data type
{
while( this.hasNext() )
{
System.out.println(this.next());
}
}
I under stand how to iterate through one linked list but am not sure how to go to the next index of the the arraylist in order to get every linked list any help would be much appreciated
Since you have an ArrayList of LinkedLists, you can get each LinkedList with the following code, and do whatever you want to do with the LinkedLists...
ArrayList<LinkedList> myaol = new ArrayList<>();
Iterator<LinkedList> itr = myaol.iterator();
while (itr.hasNext()) {
LinkedList myList = itr.next();
}
You can print the list like that
// print the list
System.out.println("LinkedList:" + myList);
// create an array and copy the list to it
Object[] array = myList.toArray();
// print the array
for (int i = 0; i < myList.size(); i++) {
System.out.println("Array:" + array[i]);
}

How to find sublist (intersection) among items in one Arraylist of integer in java?

I have a Hashtable<List<Integer>, List<Triples>> ResultIPM2 = new HashTable<>(), I want to work on the key part which is aList<Integer>contains three patterns {[2,3,4] , [3,2,4,3] , [2,4,3]}.What I want to do is, I want to remove [2,4,3] because it is a subset of [3,2,4,3]. How can I report just [2,4,3] and [3,2,4,3] .
Note that the intersection must be in the same order as the smaller list.
For example, if instead of [3,2,4,3] we had a pattern [3,2,3,4] we wouldn't remove any pattern. by "remove" I mean not showing the pattern when reporting it.Here is a piece of my code:
Please don't care about the other answers because I had to edit this old question in order to be able to ask a new question.Thank you
Set<List<Integer>> key = resultsIPM2.keySet();
boolean maximal = false;
for(List<Integer> p1 : key){
for(List<Integer> p2:key){
if(!p2.equals(p1)){
if(p1.containsAll(p2)){
System.out.println(p1);
}
}
}
}
You can't use the enhanced for loop to remove from the list. Use an explicit Iterator.
List<List<Pair>> newPattern = new CopyOnWriteArrayList<>();
//Algorithm : end of Line 14
Iterator<List<Pair> iter = ptList.iterator();
while(iter.hasNext()){
List<Pair> list = iter.next();
Iterator<Pair> pairIter = list.iterator();
while(pairIter.hasNext()){
Pair pair = pairIter.next();
if (getFrequency(pair) < minSupp){
pairIter.remove();
newPattern.add(list);
}
}
}
Iterator.remove() is the only safe way to modify a collection during iteration.
Use Iterator instead of the for-each construct when you need to remove the current element.
The for-each construct hides the iterator, so you cannot call remove. Therefore, the for-each construct is not usable for filtering.
Now regarding the code which you said dint work is because
Iterator <Pair> iter = pairList.iterator();
should be something like this
Iterator<List<Pair> iter = ptList.iterator();
then again when you do iter.next();
It will give you List<Pair> list not this Pair pair. So you need to iterate over the list again the compare and remove.
Eran gave you a very nice example follow that
You can not modify a List while you are in a foreach loop of this list. You can use a normal for-loop which just increments an int to get your element:
List<List<Pair>> newPattern = new CopyOnWriteArrayList<>();
//Algorithm : end of Line 14
for(int i = 0; i < ptList.size(); i++){
List<Pair> list = ptList.get(i);
for(int j = 0; j < list.size(); j++){
Pair pair = list.get(j);
if (getFrequency(pair) < minSupp){
list.remove(j);
j--;
newPattern.add(list);
}
}
}

How to combine 2 Vectors in a JList?

Vector<String> totalProducts = Products.getProductNames();
Vector<String> selectedProducts = Products.getSelectedProductNames();
The selectedProducts vector is a subvector of totalProducts (meaning that selectedProducts contains one, more or all of the elements from totalProducts). What I want is to combine these two vectors and make a single JList, which contains all the elements from totalProducts, and with the elements of selectedProducts already selected.
What I tried:
Vector<Integer> indices = new Vector<Integer>();
JList prdList = new JList(totalProducts);
for(int i = 0; i < totalProducts.size(); i++)
{
for(String name : selectedProducts)
{
if(totalProducts.contains(name)) indices.add(i);
}
}
Object [] objIndices = indices.toArray();
//... Cast from Object [] to int [] ....
prdList.setSelectedIndices(intIndices);
...but this selects all the elements in the final JList.
Previously I tried:
JList prdList = new JList(totalProducts);
for(String tName : totalProducts)
{
for(String sName : selectedProducts)
{
if(totalProducts.contains(sName)) prdList.setSelectedValue(sName, false);
}
}
...but this one selected only the last element from the selectedProducts.
Can you please help me to do it right?
Your attempt that selects all items does so because you're iterating over each item, and if any item from the selectedProducts list is in the total list, adds the iteration item's index to the final selection list. Try changing your loop to something like this:
for(int i = 0; i < totalProducts.size(); i++)
{
String name = totalProducts.get(i);
if(selectedProducts.contains(name)) indices.add(i);
}
in debugging your first attempt (which looks like it should work, what was the contents of your intIndices array? because that looks like it should work, presuming your array conversion works.
however, since selectedproducts is guaranteed to be less items than total, you might want to iterate over that instead?
List<Integer> indices = new ArrayList<Integer>(selectedProducts.size());
for(String name : selectedProducts)
{
int index = totalProducts.indexOf(name);
if (index != -1)
indices.add(index);
}
although, since indexOf is a linear search through a list, it probably doesn't make much of a difference either way.
as for your second attempt, the ListSelectionModel has methods for adding a selected index (addSelectionInterval(int index0, int index1))
, you're using the one that sets (overwrites) the selection.
see http://download.oracle.com/javase/6/docs/api/javax/swing/ListSelectionModel.html
aside: you might want to use List<> instead of Vector<>, as vector has a lot of unecessary synchronization overhead. Unless you need the synchronization....
edit fixed copy+paste of add(i) with add(index)

Categories