I needed to create an arraylist without an element of another arraylist, but I need this new arraylist to keep updating. For example, an element of the old arraylist is removed, also remove in the new one.
But I did not want to remove the element of the two arraylist, only the old one, so as not to have much code
(My method "showPeople" is updated every 1 second)
My code:
ArrayList<Person> personList = new ArrayList<>();
private void method(){
personList.add(new People("Name"))
}
private void showPeople(){
ArrayList<Person> newPersonList =
new ArrayList<>(personList.stream()
.filter(person -> !person.getName().equals("Test"))
.collect(Collectors.toList()))
for (int i = 0; i < newPersonList.size(); i++){
gui.show(newPersonList.get(i).getName());
}
}
The problem is that when I create the new arraylist and remove an item from the old one, the new one does not update
You're making multiple copies of your list; instead, do something like:
List<Person> filterPeople(List<Person> people, #NotNull String name) {
return people.stream()
.filter(person -> !name.equals(person.getName()))
.collect(Collectors.toList());
}
If you're uncomfortable with the lack of guarantees on the the shape of the List, you can be explicit:
.collect(Collectors.toCollection(ArrayList::new));
It's still unclear what you're asking, however. I suggest you provide a minimal, complete, and verifiable example.
If you want the list without the element to keep updating, you can create a view of the list by extending AbstractList.
The API documentation contains instructions as to the methods you would need to override. If you don't want the list to be modifiable through the view, all you need to do is to override the get and size methods:
class ListView extends AbstractList<String> {
private final List<String> delegate; // Initialize in constructor.
public T get(int i) {
int pos = delegate.indexOf("Test");
if (pos < 0 || i < pos) return delegate.get(i);
return delegate.get(i + 1);
}
public int size() {
return delegate.size() - (delegate.contains("Test") ? 1 : 0);
}
}
This will repeatedly search for the "Test" element, because there is no way for the view to know if the delegate list has been updated underneath it.
Here's a handy method:
private static <T> List<T> CopyListWithoutItem(List<T> listToCopy, T itemToNotCopy) {
return listToCopy.stream().filter(item -> !item.equals(itemToNotCopy)).collect(Collectors.toList());
}
You can use that: List<String> elements = list.stream().distinct().collect(Collectors.toList());
That will remove duplicates.
Related
I have 3 lists which describe user: status, name, email. I need to put each elements from each list into an object(e.g get each first element from each list and put them into UserItem and add object to list, so it describes my 1st user and so on). I use following solution, but I want to know is there any design pattern to solve this in more efficient way? I want to avoid classic for loops(ive tried to find solution using stream api, but vainly).
public List<UserItem> mapToObject(final List<String> statusList, final List<String> nameList, final List<String> emailList) {
for (int i = 0; i < emailList.size(); i++) {
var item = new UserItem();
item.setStatus(statusList.get(i));
item.setName(nameList.get(i));
item.setEmail(emailList.get(i));
setItem(item);
}
return getItems();
}
For making objects using data gathered from lists or any kind of array type data objects, you need looping, so you should use for loop, while loop or as in comments the forEach loop.
If you need some design pattern answer I'll go with using an iterator for each list.
public List<UserItem> mapToObject(final List<String> statusList, final List<String> nameList, final List<String> emailList) {
List<UserItem> users = new ArrayList<>();
Iterator statusIt = statusList.iterator();
Iterator nameIt = nameList.iterator();
Iterator emailIt = emailList.iterator();
while (statusIt.hasNext() && nameIt.hasNext() && emailIt.hasNext()) {
UserItem item = new UserItem();
item.setStatus((String)statusIt.next());
item.setName((String)nameIt.next());
item.setEmail((String)emailIt.next());
users.add(item);
}
return users;
}
After reading several questions and examples I came with this example which I modified a bit to make it work as expected.
Collections.sort(listToOrder, Comparator.comparing(item -> someObject.getListOfLongs().indexOf(item.getId())));
So listToOrder is a list of MyObject which has name and id, so I need to order listToOrder in the same order as listOfLongs.
With the example of code given it work as expected however if the listToOrder is different in size it fails, wondering how I could make it to work even if the sizes are different.
Edit:
I misread, the error I was getting was an IndexOutOfBoundsException which wasn't triggered by the line of code I put up there, it was because of a manual log.
List.indexOf() returns -1 if the element is not found, which means such items will be ordered first in the resulting sorted list.
Without ordering data, the only other sensible way to handle such elements is to order them last:
Collections.sort(listToOrder, Comparator.comparing(item -> someObject.getListOfLongs().contains(item.getId()) ? someObject.getListOfLongs().indexOf(item.getId()) : Integer.MAX_VALUE));
This has nothing to do with sorting, but ordering. Having the following object with full-args constructor and getters:
public static class MyObject {
private final long id;
private final String name;
}
... and the following data in a random order ...
List<Integer> ids = Arrays.asList(5,4,7,0,2,1,3,8,6);
List<MyObject> list = Arrays.asList(
new MyObject(1, "one"),
new MyObject(3, "three"),
...
new MyObject(6, "six"),
new MyObject(8, "eight")
);
The solution you are looking for is this:
List<MyObject> newList = new ArrayList<>(list);
for (int i=0; i<ids.size(); i++) {
int id = ids.get(i);
for (MyObject myObject: list) {
if (myObject.getId() == id) {
newList.set(i, myObject);
break;
}
}
}
Simply find the object with the matching ID and set it to a new list. There is no dedicated method to do that.
I have a list of objects and I want to iterate through the sublist starting with the object that meets a certain criterion.
(Concretely, the list of declared fields for a class, starting with field such-and-such, known by name not by integer index.)
Obviously one solution would be to iterate through the entire list, setting a flag when the particular object has been found, but it occurs to me to wonder whether Java 8 with its improved support for higher-order programming, provides a more elegant way to do it.
What's the most elegant/idiomatic way to do this in Java 8? (Performance isn't a consideration; the code in question will only be run once per program execution.)
It seems that you want the indexOf method to act like as a predicate, where you can give a custom property to tell whether you find the first object that satisfies it.
It can be done using an helper method.
static <T> List<T> getSubList(List<T> list, Predicate<T> pred){
return list.subList(list.indexOf(list.stream().filter(pred).findFirst().get()), list.size());
}
What it does is:
get a Stream<T> from the list
apply a filter to it
find the first element that satisfied the given predicate
get the object in the resulting Optional<T> calling get()
use indexOf on the list to get the index of this object
return a sublist of the original list
Then you can call it like;
List<MyClass> subList = getSubList(list, o -> o.b.startsWith("10"));
For a small example, here's how you can take a sublist from the first object where its String value starts with a 10 until the end of the list.
public class Test {
public static void main(String[] args) {
List<MyClass> list = new ArrayList<>();
for(int i = 0; i < 15; i++){
list.add(new MyClass(i, String.valueOf(i)));
}
System.out.println(getSubList(list, o -> o.s.startsWith("10"))); //[MyClass [a=10, b=10], MyClass [a=11, b=11], MyClass [a=12, b=12], MyClass [a=13, b=13], MyClass [a=14, b=14]]
}
static <T> List<T> getSubList(List<T> list, Predicate<T> pred){
return list.subList(list.indexOf(list.stream().filter(pred).findFirst().get()), list.size());
}
}
class MyClass {
int i;
String s;
public MyClass(int i,String s){
this.i = i;
this.s = s;
}
#Override
public String toString() {
return "MyClass [i=" + i + ", s=" + s + "]";
}
}
You can add more checks, for example to see if you have a value from the Optional (using isPresent()) you get by calling findFirst, but you have the main idea of how to do it.
Hope it helps! :)
With Guava, you can do
// list is an instance of List<T> from which the sublist is wanted
Iterable<T> sublist = Iterables.skip(list, list.indexOf(certainObject));
However, this does not use any new features of Java 8.
You could:
List<T> list = ...;
Optional<T> first = list.stream()
.filter(f -> f.name.equals("field name"))
.findFirst();
return first.isPresent()
? list.subList(list.indexOf(first))
: Collections.emptyList();
ps: on mobile so not sure it compiles but the general idea should work.
I have an ArrayList that I want to iterate over. While iterating over it I have to remove elements at the same time. Obviously this throws a java.util.ConcurrentModificationException.
What is the best practice to handle this problem? Should I clone the list first?
I remove the elements not in the loop itself but another part of the code.
My code looks like this:
public class Test() {
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff() {
for (A a : abc)
a.doSomething();
}
public void removeA(A a) {
abc.remove(a);
}
}
a.doSomething might call Test.removeA();
Two options:
Create a list of values you wish to remove, adding to that list within the loop, then call originalList.removeAll(valuesToRemove) at the end
Use the remove() method on the iterator itself. Note that this means you can't use the enhanced for loop.
As an example of the second option, removing any strings with a length greater than 5 from a list:
List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String value = iterator.next();
if (value.length() > 5) {
iterator.remove();
}
}
From the JavaDocs of the ArrayList
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.
You are trying to remove value from list in advanced "for loop", which is not possible, even if you apply any trick (which you did in your code).
Better way is to code iterator level as other advised here.
I wonder how people have not suggested traditional for loop approach.
for( int i = 0; i < lStringList.size(); i++ )
{
String lValue = lStringList.get( i );
if(lValue.equals("_Not_Required"))
{
lStringList.remove(lValue);
i--;
}
}
This works as well.
In Java 8 you can use the Collection Interface and do this by calling the removeIf method:
yourList.removeIf((A a) -> a.value == 2);
More information can be found here
You should really just iterate back the array in the traditional way
Every time you remove an element from the list, the elements after will be push forward. As long as you don't change elements other than the iterating one, the following code should work.
public class Test(){
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff(){
for(int i = (abc.size() - 1); i >= 0; i--)
abc.get(i).doSomething();
}
public void removeA(A a){
abc.remove(a);
}
}
While iterating the list, if you want to remove the element is possible. Let see below my examples,
ArrayList<String> names = new ArrayList<String>();
names.add("abc");
names.add("def");
names.add("ghi");
names.add("xyz");
I have the above names of Array list. And i want to remove the "def" name from the above list,
for(String name : names){
if(name.equals("def")){
names.remove("def");
}
}
The above code throws the ConcurrentModificationException exception because you are modifying the list while iterating.
So, to remove the "def" name from Arraylist by doing this way,
Iterator<String> itr = names.iterator();
while(itr.hasNext()){
String name = itr.next();
if(name.equals("def")){
itr.remove();
}
}
The above code, through iterator we can remove the "def" name from the Arraylist and try to print the array, you would be see the below output.
Output : [abc, ghi, xyz]
Do the loop in the normal way, the java.util.ConcurrentModificationException is an error related to the elements that are accessed.
So try:
for(int i = 0; i < list.size(); i++){
lista.get(i).action();
}
Here is an example where I use a different list to add the objects for removal, then afterwards I use stream.foreach to remove elements from original list :
private ObservableList<CustomerTableEntry> customersTableViewItems = FXCollections.observableArrayList();
...
private void removeOutdatedRowsElementsFromCustomerView()
{
ObjectProperty<TimeStamp> currentTimestamp = new SimpleObjectProperty<>(TimeStamp.getCurrentTime());
long diff;
long diffSeconds;
List<Object> objectsToRemove = new ArrayList<>();
for(CustomerTableEntry item: customersTableViewItems) {
diff = currentTimestamp.getValue().getTime() - item.timestamp.getValue().getTime();
diffSeconds = diff / 1000 % 60;
if(diffSeconds > 10) {
// Element has been idle for too long, meaning no communication, hence remove it
System.out.printf("- Idle element [%s] - will be removed\n", item.getUserName());
objectsToRemove.add(item);
}
}
objectsToRemove.stream().forEach(o -> customersTableViewItems.remove(o));
}
One option is to modify the removeA method to this -
public void removeA(A a,Iterator<A> iterator) {
iterator.remove(a);
}
But this would mean your doSomething() should be able to pass the iterator to the remove method. Not a very good idea.
Can you do this in two step approach :
In the first loop when you iterate over the list , instead of removing the selected elements , mark them as to be deleted. For this , you may simply copy these elements ( shallow copy ) into another List.
Then , once your iteration is done , simply do a removeAll from the first list all elements in the second list.
In my case, the accepted answer is not working, It stops Exception but it causes some inconsistency in my List. The following solution is perfectly working for me.
List<String> list = new ArrayList<>();
List<String> itemsToRemove = new ArrayList<>();
for (String value: list) {
if (value.length() > 5) { // your condition
itemsToRemove.add(value);
}
}
list.removeAll(itemsToRemove);
In this code, I have added the items to remove, in another list and then used list.removeAll method to remove all required items.
Instead of using For each loop, use normal for loop. for example,the below code removes all the element in the array list without giving java.util.ConcurrentModificationException. You can modify the condition in the loop according to your use case.
for(int i=0; i<abc.size(); i++) {
e.remove(i);
}
Sometimes old school is best. Just go for a simple for loop but make sure you start at the end of the list otherwise as you remove items you will get out of sync with your index.
List<String> list = new ArrayList<>();
for (int i = list.size() - 1; i >= 0; i--) {
if ("removeMe".equals(list.get(i))) {
list.remove(i);
}
}
You can also use CopyOnWriteArrayList instead of an ArrayList. This is the latest recommended approach by from JDK 1.5 onwards.
Do somehting simple like this:
for (Object object: (ArrayList<String>) list.clone()) {
list.remove(object);
}
An alternative Java 8 solution using stream:
theList = theList.stream()
.filter(element -> !shouldBeRemoved(element))
.collect(Collectors.toList());
In Java 7 you can use Guava instead:
theList = FluentIterable.from(theList)
.filter(new Predicate<String>() {
#Override
public boolean apply(String element) {
return !shouldBeRemoved(element);
}
})
.toImmutableList();
Note, that the Guava example results in an immutable list which may or may not be what you want.
for (A a : new ArrayList<>(abc)) {
a.doSomething();
abc.remove(a);
}
"Should I clone the list first?"
That will be the easiest solution, remove from the clone, and copy the clone back after removal.
An example from my rummikub game:
SuppressWarnings("unchecked")
public void removeStones() {
ArrayList<Stone> clone = (ArrayList<Stone>) stones.clone();
// remove the stones moved to the table
for (Stone stone : stones) {
if (stone.isOnTable()) {
clone.remove(stone);
}
}
stones = (ArrayList<Stone>) clone.clone();
sortStones();
}
I arrive late I know but I answer this because I think this solution is simple and elegant:
List<String> listFixed = new ArrayList<String>();
List<String> dynamicList = new ArrayList<String>();
public void fillingList() {
listFixed.add("Andrea");
listFixed.add("Susana");
listFixed.add("Oscar");
listFixed.add("Valeria");
listFixed.add("Kathy");
listFixed.add("Laura");
listFixed.add("Ana");
listFixed.add("Becker");
listFixed.add("Abraham");
dynamicList.addAll(listFixed);
}
public void updatingListFixed() {
for (String newList : dynamicList) {
if (!listFixed.contains(newList)) {
listFixed.add(newList);
}
}
//this is for add elements if you want eraser also
String removeRegister="";
for (String fixedList : listFixed) {
if (!dynamicList.contains(fixedList)) {
removeResgister = fixedList;
}
}
fixedList.remove(removeRegister);
}
All this is for updating from one list to other and you can make all from just one list
and in method updating you check both list and can eraser or add elements betwen list.
This means both list always it same size
Use Iterator instead of Array List
Have a set be converted to iterator with type match
And move to the next element and remove
Iterator<Insured> itr = insuredSet.iterator();
while (itr.hasNext()) {
itr.next();
itr.remove();
}
Moving to the next is important here as it should take the index to remove element.
List<String> list1 = new ArrayList<>();
list1.addAll(OriginalList);
List<String> list2 = new ArrayList<>();
list2.addAll(OriginalList);
This is also an option.
If your goal is to remove all elements from the list, you can iterate over each item, and then call:
list.clear()
What about of
import java.util.Collections;
List<A> abc = Collections.synchronizedList(new ArrayList<>());
ERROR
There was a mistake when I added to the same list from where I took elements:
fun <T> MutableList<T>.mathList(_fun: (T) -> T): MutableList<T> {
for (i in this) {
this.add(_fun(i)) <--- ERROR
}
return this <--- ERROR
}
DECISION
Works great when adding to a new list:
fun <T> MutableList<T>.mathList(_fun: (T) -> T): MutableList<T> {
val newList = mutableListOf<T>() <--- DECISION
for (i in this) {
newList.add(_fun(i)) <--- DECISION
}
return newList <--- DECISION
}
Just add a break after your ArrayList.remove(A) statement
I want to have a reversed list view on a list (in a similar way than List#sublist provides a sublist view on a list). Is there some function which provides this functionality?
I don't want to make any sort of copy of the list nor modify the list.
It would be enough if I could get at least a reverse iterator on a list in this case though.
Also, I know how to implement this myself. I'm just asking if Java already provides something like this.
Demo implementation:
static <T> Iterable<T> iterableReverseList(final List<T> l) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return new Iterator<T>() {
ListIterator<T> listIter = l.listIterator(l.size());
public boolean hasNext() { return listIter.hasPrevious(); }
public T next() { return listIter.previous(); }
public void remove() { listIter.remove(); }
};
}
};
}
I just have found out that some List implementations have descendingIterator() which is what I need. Though there is no general such implementation for List. Which is kind of strange because the implementation I have seen in LinkedList is general enough to work with any List.
Use the .clone() method on your List. It will return a shallow copy, meaning that it will contain pointers to the same objects, so you won't have to copy the list. Then just use Collections.
Ergo,
Collections.reverse(list.clone());
If you are using a List and don't have access to clone() you can use subList():
List<?> shallowCopy = list.subList(0, list.size());
Collections.reverse(shallowCopy);
Guava provides this: Lists.reverse(List)
List<String> letters = ImmutableList.of("a", "b", "c");
List<String> reverseView = Lists.reverse(letters);
System.out.println(reverseView); // [c, b, a]
Unlike Collections.reverse, this is purely a view... it doesn't alter the ordering of elements in the original list. Additionally, with an original list that is modifiable, changes to both the original list and the view are reflected in the other.
If i have understood correct then it is one line of code .It worked for me .
Collections.reverse(yourList);
Its not exactly elegant, but if you use List.listIterator(int index) you can get a bi-directional ListIterator to the end of the list:
//Assume List<String> foo;
ListIterator li = foo.listIterator(foo.size());
while (li.hasPrevious()) {
String curr = li.previous();
}
I use this:
public class ReversedView<E> extends AbstractList<E>{
public static <E> List<E> of(List<E> list) {
return new ReversedView<>(list);
}
private final List<E> backingList;
private ReversedView(List<E> backingList){
this.backingList = backingList;
}
#Override
public E get(int i) {
return backingList.get(backingList.size()-i-1);
}
#Override
public int size() {
return backingList.size();
}
}
like this:
ReversedView.of(backingList) // is a fully-fledged generic (but read-only) list
java.util.Deque has descendingIterator() - if your List is a Deque, you can use that.
Collections.reverse(nums) ... It actually reverse the order of the elements.
Below code should be much appreciated -
List<Integer> nums = new ArrayList<Integer>();
nums.add(61);
nums.add(42);
nums.add(83);
nums.add(94);
nums.add(15);
//Tosort the collections uncomment the below line
//Collections.sort(nums);
Collections.reverse(nums);
System.out.println(nums);
Output: 15,94,83,42,61
I know this is an old post but today I was looking for something like this. In the end I wrote the code myself:
private List reverseList(List myList) {
List invertedList = new ArrayList();
for (int i = myList.size() - 1; i >= 0; i--) {
invertedList.add(myList.get(i));
}
return invertedList;
}
Not recommended for long Lists, this is not optimized at all. It's kind of an easy solution for controlled scenarios (the Lists I handle have no more than 100 elements).
Hope it helps somebody.
You can also invert the position when you request an object:
Object obj = list.get(list.size() - 1 - position);
For small sized list we can create LinkedList and then can make use of descending iterator as:
List<String> stringList = new ArrayList<>(Arrays.asList("One", "Two", "Three"));
stringList.stream().collect(Collectors.toCollection(LinkedList::new))
.descendingIterator().
forEachRemaining(System.out::println); // Three, Two, One
System.out.println(stringList); // One, Two, Three
You can also do this:
static ArrayList<String> reverseReturn(ArrayList<String> alist)
{
if(alist==null || alist.isEmpty())
{
return null;
}
ArrayList<String> rlist = new ArrayList<>(alist);
Collections.reverse(rlist);
return rlist;
}