I have created a collection and filled it with elements which are collections too, but when I tried to iterate through this container using a foreach construction (or other methods) it returns me nothing, I tried to get size() and saw what I expect (appropriate number) but seems like nevertheless container not empty inside each collection is null
Code snippet example:
Item it1, it2;
List<Collection<Item>> hull = new ArrayList<Collection<Item>>();
List<Item> seq = new ArrayList<Item>();
seq.add(it1);
hull.add(seq);
seq.clear();
seq.add(it2);
hull.add(seq);
for (<Collection<Item> c: hull)
System.out.println(c);
This is just an simplified snippet of what I do
Please suggest alternatives. Where did I make a mistake?
Each time you call seq.clear() you empty the inner ArrayList. Don't forget that when you add an object to a Collection, you only add the reference. You don't clone the Object. You should create a new ArrayList Object at each iteration.
E.g.
List<Collection<Item>> hull = new ArrayList<Collection<Item>>();
List<Item> seq = new ArrayList<Item>();
seq.add(it1);
hull.add(seq);
List<Item> seq2 = new ArrayList<Item>();
seq2.add(it2)
hull.add(seq2);
EDIT:
Complete Sample that compiles:
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class NewClass1 {
static class Item {
String a;
public Item(String a) {
this.a = a;
}
#Override
public String toString() {
return a;
}
}
public static void main(String[] args) {
List<Collection<Item>> hull = new ArrayList<Collection<Item>>();
List<Item> seq = new ArrayList<Item>();
Item it1 = new Item("item 1");
seq.add(it1);
hull.add(seq);
List<Item> seq2 = new ArrayList<Item>();
Item it2 = new Item("item 2");
seq2.add(it2);
hull.add(seq2);
for (Collection<Item> current : hull) {
for (Item item : current) {
System.out.println(item);
}
}
}
}
Output:
run:
item 1
item 2
Your code, corrected to compile:
package sample;
import java.util.ArrayList;
import java.util.List;
public class Item {
public static void main( String[] args ) {
List< List< Item >> hull = new ArrayList<>();
List< Item > seq = new ArrayList<>();
seq.add( new Item());
hull.add( seq );
seq = new ArrayList<>(); // in place of seq.clear();
seq.add( new Item());
hull.add( seq );
for( List<Item> c: hull ) {
System.out.println( c.get( 0 ));
}
}
}
ouputs:
sample.Item#6da264f1
sample.Item#40914272
As you can see, there is no problem.
In order to iterate through a collection of collections you need a nested foreach.
for(Collection<Item> c: hull)
{
for(Item i: c)
{
}
}
By the way, are you aware that it1 and it2 are not initialized and that's why you are getting nothing?
size() will always give you the size of the collections, but they might be containing nulls (as it is your case).
Related
I have a requirement related to Streams in Java.
I need to iterate over a List of Objects,where each object has Integer property and a List property.
What I need is, if same objects has the same ID, I need to concat the lists.
Let me illustrate the example with a little bit of a simple code:
Here just defining 2 simple classes:
public static class Wrapper {
Integer id ;
List<Element> list;
public Wrapper(Integer id, List<Element> list) {
this.id = id;
this.list = list;
}
}
public static class Element {
String content ;
public Element(String content) {
this.content = content;
}
}
Now in a Main Java method,creating same objects for the porpuse of the example:
List<Wrapper> list=new ArrayList();
ArrayList<Element> listForWrapper1= new ArrayList();
listForWrapper1.add(new Element("Content A"));
listForWrapper1.add(new Element("Content B"));
ArrayList<Element> listForWrapper2= new ArrayList();
listForWrapper2.add(new Element("Content C"));
listForWrapper2.add(new Element("Content D"));
ArrayList<Element> listForWrapper3= new ArrayList();
listForWrapper3.add(new Element("Content E"));
listForWrapper3.add(new Element("Content F"));
Wrapper wrapper1=new Wrapper(1,listForWrapper1);
Wrapper wrapper2=new Wrapper(2,listForWrapper2);
//Here this Wrapper has the same ID than wrapper2
Wrapper wrapper3=new Wrapper(2,listForWrapper3);
//Adding Elements to List
list.add(wrapper1);
list.add(wrapper2);
list.add(wrapper3);
As you can see, I am adding 3 Wrappers to the list, BUT 2 of them have the same ID
What I want is when Wrapper IDs are the same in the array,just merge both list. So in this example the result should be:
A list with 2 Element:
Element 1 : Wrapper Object with ID 1,with 2 Elements inside its list property,Element Content A ,and Element Content B
Element 2: Wrapper Object with ID 2,with 4 Elements inside its list property,Element Content C,Element Content D,Element Content E and Element Content F.
How can I achieve this result using Streams? I cant think any elegant solution!
Thanks in advance!
List<Wrapper> combinedList=list.stream().....
You could use BinaryOperator<U> mergeFunction in Collectors.toMap`.
Collection<Wrapper> wrapperList = wrappers.stream()
.collect(Collectors.toMap(Wrapper::getId, x -> x),
(oldVal, newVal) -> {
oldVal.getElements().addAll(newVal.getElements());
return oldVal;
}))
.values();
In the above code I have written mergeFunction to always return oldVal (oldVal, newVal) -> oldVal but you can change the way you want. Lambda function x -> x can also be written as Function.identity().
You can use Collectors.toMap() to add the values of the map using a merge function.
Map<Integer, Wrapper> collect =
list.stream()
.collect(Collectors.toMap(w -> w.id,
w -> w,
(w1, w2) -> {
w1.list.addAll(w2.list);
return w1;
})
);
Working
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<Wrapper> list=new ArrayList();
ArrayList<Element> listForWrapper1= new ArrayList();
listForWrapper1.add(new Element("Content A"));
listForWrapper1.add(new Element("Content B"));
ArrayList<Element> listForWrapper2= new ArrayList();
listForWrapper2.add(new Element("Content C"));
listForWrapper2.add(new Element("Content D"));
ArrayList<Element> listForWrapper3= new ArrayList();
listForWrapper3.add(new Element("Content E"));
listForWrapper3.add(new Element("Content F"));
Wrapper wrapper1=new Wrapper(1,listForWrapper1);
Wrapper wrapper2=new Wrapper(2,listForWrapper2);
//Here this Wrapper has the same ID than wrapper2
Wrapper wrapper3=new Wrapper(2,listForWrapper3);
//Adding Elements to List
list.add(wrapper1);
list.add(wrapper2);
list.add(wrapper3);
Map<Integer, Wrapper> collect =
list.stream()
.collect(Collectors.toMap(w -> w.id,
w -> w,
(w1, w2) -> {
w1.list.addAll(w2.list);
return w1;
})
);
System.out.println( collect.values() );
}
}
class Wrapper {
Integer id ;
List<Element> list;
public Wrapper(Integer id, List<Element> list) {
this.id = id;
this.list = list;
}
#Override
public String toString() {
return id + ":" + list;
}
}
class Element {
String content ;
public Element(String content) {
this.content = content;
}
#Override
public String toString() {
return content;
}
}
Output
[1:[Content A, Content B], 2:[Content C, Content D, Content E, Content F]]
You can try this:
Map<Integer, Wrapper> map = list.stream().collect(Collectors.toMap(wrapper -> wrapper.id /*Use the ids as the keys*/, wrapper -> wrapper /*Return the same wrapper as the value*/, (w1, w2) -> {
w1.list.addAll(w2.list); // If a wrapper with the same id is found, then merge the list of wrapper 2 to the list of wrapper 1 and return wrapper 1.
return w1;
}));
list = new ArrayList<>(map.values()); // Create new ArrayList with the values of the map.
System.out.println(list); // [cci.Test$Wrapper#4eec7777, cci.Test$Wrapper#3b07d329]
I am trying to delete the elements from list1 that are in list1
package listCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Arry2List {
public static void main(String[] args) {
String[] s = {"INDIA" ,"JAPAN","THAILAND","MALAYSIA"};
ArrayList<String> list1= new ArrayList<String>();
String[] s1 = {"THAILAND","MALAYSIA"};
ArrayList<String> list2= new ArrayList<String>();
for(String temp : s)
{
list1.add(temp);
}
for(String temp : s1)
{
list2.add(temp);
}
//removing elements from list1 that are in list2
System.out.println("In list1 **************");
for (String t : list1)
{
System.out.println(t);
}
System.out.println("In list2 **************");
for (String t1 : list2)
{
System.out.println(t1);
}
//editlist(list1,list2);
Iterator<String> i=list1.iterator();
while( i.hasNext() )
{
if ( list2.contains( i.hasNext() ) )
{
i.remove();
}
}
System.out.println("In list1 again **************");
for(int i1 =0;i1<list1.size();i1++)
{
System.out.println(list1.get(i1));
}
}
}
Output should be INDIA,JAPAN.
List1 should contain only those elements which are not in the list2.
I am a beginner to Core Java and trying to learn collections.
In the loop that checks the element using List.contains(), you're passing a boolean (i.hasNext() returns whether the iterator has more elements) instead of the element. This causes the loop to run infinitely because you never call Iterator.next() to get the next element. You should use:
if (list2.contains(i.next())) {
instead of
if (list2.contains(i.hasNext())) {
It's better practice to also save the next element in a variable for re-usability:
while (i.hasNext()) {
String element = i.next();
if (list2.contains(element)) {
i.remove();
}
}
There is a built-in method to do that:
list1.removeAll(list2)
[EDIT]
You can create the lists easier using Arrays.asList:
List<String> list1 = new ArrayList<String>(Arrays.asList("INDIA", "JAPAN", "THAILAND", "MALAYSIA"));
List<String> list2 = Arrays.asList("THAILAND", "MALAYSIA");
list1.removeAll(list2);
[EDIT2]
The Arrays.asList produces unmodifiable list, so we have to use it to initialize a modifiable one.
[EDIT3]
Your code doesn't work because you don't advance the iterator. i.hasNext() only checks if there is a next element. It returns true or false, not the element itself. Here is how to fix this:
while (i.hasNext()) {
if (list2.contains(i.next())) {
i.remove();
}
}
You can also iterate over the list2 elements and remove them from list1:
for (String el : list2) {
list1.remove(el);
}
This question already has answers here:
Java Beginner: How do I link one linked list to another?
(6 answers)
Closed 8 years ago.
I hava list of LinkedList and I want to make (unable to modified) One connected LinkedList .
and not change the original linkedLists.
LinkedLists<String> a=new LinkedList<String>();
LinkedLists<String> b=new LinkedList<String>();
LinkedLists<String> c=new LinkedList<String>();
a.add("as");
a.add("sa");
a.add("bb");
b.add("as");
b.add("sa");
c.add("bb");
c.add("d");
c.add("ya");
the new LinkedList contain ya d bb sa as bb sa as
so I want to make one Linked List.I preffer Not copy the items casue this consume memory.
Only connect theme for go all over the items not to modified the items.
Thanks!
Try Collections#unmodifiableList()
Sample code:
LinkedList<String> a = new LinkedList<String>();
a.add("as");
a.add("sa");
a.add("bb");
a.add("as");
a.add("sa");
a.add("bb");
a.add("d");
a.add("ya");
List<String> b = Collections.unmodifiableList(a.subList(0, 3));
List<String> c = Collections.unmodifiableList(a.subList(5, 8));
b.set(0, "aa"); // not allowed
c.add("zz"); // not allowed
a.set(6, "zz"); // allowed and List c is also updated.
Try subclassing List. Here's a quick example I put together below. It's largely incomplete but you'll get the idea.
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class Experiment {
public static void main(String[] args) throws Exception {
LinkedList<String> a = new LinkedList<String>();
LinkedList<String> b = new LinkedList<String>();
LinkedList<String> c = new LinkedList<String>();
a.add("as");
a.add("sa");
a.add("bb");
b.add("as");
b.add("sa");
c.add("bb");
c.add("d");
c.add("ya");
MyLinkedList<String> list = new MyLinkedList<String>();
list.add(a);
list.add(b);
list.add(c);
for (String s : list) {
System.out.println(s);
}
}
private static class MyLinkedList<T> extends LinkedList<T> {
private List<List<T>> lists = new LinkedList<List<T>>();
public void add(LinkedList<T> list) {
lists.add(list);
}
#Override
public Iterator<T> iterator() {
return new MyLinkedIterator<T>(lists);
}
}
private static class MyLinkedIterator<T> implements Iterator<T> {
private List<List<T>> lists;
private int listIndex = 0;
private int currentIndex = 0;
private T next;
public MyLinkedIterator(List<List<T>> lists) {
this.lists = lists;
}
public boolean hasNext() {
if (listIndex >= lists.size()) return false;
List<T> list = lists.get(listIndex);
if (currentIndex >= list.size()) {
currentIndex = 0;
listIndex++;
return hasNext();
}
next = list.get(currentIndex++);
return true;
}
public T next() {
return next;
}
public void remove() {
}
}
}
How about this:
LinkedList<String> a=new LinkedList<String>();
LinkedList<String> b=new LinkedList<String>();
LinkedList<String> c=new LinkedList<String>();
a.add("as");
a.add("sa");
a.add("bb");
b.add("as");
b.add("sa");
c.add("bb");
c.add("d");
c.add("ya");
LinkedList<String> unionList = new LinkedList<String>();
unionList.addAll(a);
unionList.addAll(b);
unionList.addAll(c);
LinkedList<String> unmodifiableUnion = Collections.unmodifiableList(unionList);
It uses addAll() to add all lists into a new one and returns an unmodifiable list from it using Collections.unmodifiableList()
Update
If memory consumption is your problem, the standard JDK is not enough. You will have to implement your own or use an existing one.
To implement your own you can usa a LinkedList<List<T>> to store your linked lists and implement the List interface. mprivat started an implementation for you.
To use an existing one, you could use:
Trove: it is considered really good and fast if no fastest with least memory consumption, at least that is what I have observed in my usages of it.
this implementation: it is a singly linked list so it consumes less memory and has a merge method that will merge 2 linked lists using their "pointers" as you would expect.
I have an array list which when populated has a key and a value I want to know if there is a way of splitting it on repeating keys for example my current data is like this:
[RoleID_123.0, UserHandel_tom, Password_12345.0, prevPassword_null, userCaption_thomas, Email_tom#tom.tom, RoleID_124.0, UserHandel_dave, Password_ghadf, prevPassword_sdfsd, userCaption_david, Email_dave#dave.dave, RoleID_125.0, UserHandel_trevor, Password_tre, prevPassword_null, userCaption_trev, Email_trev#trev.trev]
I want it to come out more like this:
[RoleID_123.0, UserHandel_tom, Password_12345.0, prevPassword_null, userCaption_thomas, Email_tom#tom.tom]
[RoleID_124.0, UserHandel_dave, Password_ghadf, prevPassword_sdfsd, userCaption_david, Email_dave#dave.dave]
[RoleID_125.0, UserHandel_trevor, Password_tre, prevPassword_null, userCaption_trev, Email_trev#trev.trev]
Is there a way to split it on say role id or am I going about this the wrong way?
You can try by using HashMap
private static class MyItemHashMap extends HashMap {
public Item add(Item item) {
get(item).add(item);
return item;
}
public List get(Item key) {
List list = (List) get(createItemKey((Item) key));
return list == null ? createItemEntry((Item) key) : list;
}
private List createItemEntry(Item item) {
List list = new ArrayList();
put(createItemKey(item), list);
return list;
}
private Object createItemKey(Item item) {
return item.getSplitterProperty();
}
}
public static void main(String[] args) {
MyItemHashMap itemMapped = new MyItemHashMap();
List items = Arrays.asList(new Object[]{new Item("A"), new Item("B"),
new Item("C")});
for (Iterator iter = items.iterator(); iter.hasNext();) {
Item item = (Item) iter.next();
itemMapped.add(item);
}
}
If it is an ArrayList, there is no built-in function to split data like this; you will have to do it manually. If you know the number of consecutive fields that make a single structure, this shouldn't be too hard; something like this:
// 6 because there are 6 fields
for (int i = 0; i < arrayList.size(); i = i + 6) {
List thisList = arrayList.subList(i, i + 5);
// ... Now do whatever you want with thisList - it contains one structure.
}
If the number of fields can change then you'll have to do something a little more dynamic and loop through looking for a RoleID field, for example.
I'd use a HashMap to seperate the data instead of one long ArrayList ( you shouldn't have stored the data like this in the first instance )
HashMap<String,ArrayList<String>> hm = new HashMap<String,ArrayList<String>>;
// For each list:
ArrayList<String> arr = new ArrayList<String>;
arr.add("each element");
hm.put("RoleID_123.0", arr);
This way you will end up with a three dimensional structure with a key ( "RoleID..." ) pointing to its child elements.
Try this
String[] str=new String[]{"RoleID_123.0", "UserHandel_tom", "Password_12345.0", "prevPassword_null", "userCaption_thomas", "Email_tom#tom.tom", "RoleID_124.0", "UserHandel_dave", "Password_ghadf", "prevPassword_sdfsd", "userCaption_david", "Email_dave#dave.dave", "RoleID_125.0", "UserHandel_trevor", "Password_tre", "prevPassword_null", "userCaption_trev", "Email_trev#trev.trev"};
List<String> list=new ArrayList<>(Arrays.asList(str));
List<String> subList=list.subList(0,5);
You can try something similar to this
If you feel like taking a Linq-ee Libraried approach, this is about as good as it gets, and it requires use of a couple delegate objects:
import static com.google.common.collect.Collections2.filter;
import static com.google.common.collect.Collections2.transform;
//...
final List<String> yourList = //...
final int RECORD_LENGTH = 6;
Collection<String> roleIdValues = filter(yourList, new Predicate<String>() {
public boolean apply(#Nullable String input) {
return input != null && input.startsWith("RoleID");
}
});
Collection<Collection<String>> splitRecords = transform(roleIdValues, new Function<String, Collection<String>>() {
#Nullable public Collection<String> apply(#Nullable String input) {
return yourList.subList(yourList.indexOf(input), RECORD_LENGTH);
}
});
If Oracle had delivered Java 8 on time you would be able to do this in a way more slick manor. Ironically the reason you cant was provided by the same people providing the guava library
To create a List, why doesn't Java allow them to be created then elements added one by one?
This works:
public static List<TrackedItem> create(List<Item> items)
{
TrackedItem[] arr = new TrackedItem[items.size()];
int i = 0;
for (Item item : items)
{
arr[i] = TrackedItem.createOrUpdate(item);
i++;
}
return java.util.Arrays.asList(arr);
}
This does not work (tracked.add() causes a NullPointerException):
public static List<TrackedItem> create(List<Item> items)
{
List<TrackedItem> tracked = java.util.Collections.emptyList();
for (Item item : items)
{
tracked.add(TrackedItem.createOrUpdate(item));
}
return tracked;
}
java.util.Collections.emptyList();
static
List
emptyList()
Returns the empty list (immutable).
That means, you will not be able to change this list.
Its defined:
static List EMPTY_LIST
The empty list (immutable).
Quotes from Java sun reference
Edit:
To create a new list you could use e.g.
List myList = new ArrayList<MyClass>();
Use the following syntax:
public static List<TrackedItem> create(List<Item> items)
{
List<TrackedItem> tracked = new ArrayList<TrackedItem>();
for (Item item : items)
{
tracked.add(TrackedItem.createOrUpdate(item));
}
return tracked;
}
This might be a misunderstanding.
Even if it is called emptyList, it isn't a list which is just empty and ready to be populated. This emptyList is designed to be empty at all times. You can't add to this special list.
To get a 'usable' empty list you can either
List<String> list = new ArrayList<String>(); // create a new one or
list.add("if you have an list");
list.clear(); // just clear it
create a new arrayList by :
List<T> tracked = new ArrayList<T>();
List is only an interface ... you can't make a new one. you only can implement it.