Flatten nested arrays. (Java) - java

I'm struggling to create the right logic to flatten an array. I essentially want to duplicate parent rows for each child item in a nested array. The number of nested arrays could vary. I've been creating Java lists bc I find them easy to work with, but open to any solution. The nature of this problem is I'm starting with some nested JSON that I want to convert into a flat csv to load into a database table. Thanks for the help.
Example:
[1,2,[A,B,[Cat,Dog]],3]
I've created the above as a List. Each item is either a string or another List.
Result:
[1,2,A,Cat,3],
[1,2,A,Dog,3],
[1,2,B,Cat,3],
[1,2,B,Dog,3]
Here's what I have so far. Obviously not working.
private static List<List<String>> processData(List<String> row, List<Object> data, List<List<String>> rowList) {
List<List<String>> tempRowList = new ArrayList<List<String>>();
for (Object i : data) {
if (i instanceof List<?>) {
flattenArray((List<Object>) i, row, rowList);
} else {
for (List<String> r : rowList) {
r.add(i.toString()); //add item to all rows
}
}
}
return rowList;
private static void flattenArray(List<Object> arrayObject, List<String> rowToCopy, List<List<String>> rowList) {
for (Object x : arrayObject) {
if (x instanceof List<?>) {
for (List<String> t : rowList) {
flattenArray((List<Object>) x, t, rowList);
}
} else {
List<String> newRow = new ArrayList<String>(rowToCopy); //copy row
List<Object> t = new ArrayList<Object>();
t.add(x);
List<List<String>> innerRowList = new ArrayList<List<String>>();
innerRowList.add(newRow);
processData(newRow, t, innerRowList); //pass in new copied row. object to add,
rowList.add(newRow);
}
}
rowList.remove(rowToCopy);
}
And i set everything up like this.
public static void main(String[] args) {
List<Object> data = new ArrayList<Object>();
List<List<String>> rowList = new ArrayList<List<String>>();
data.add("1");
data.add("2");
List<Object> l1 = new ArrayList<Object>();
l1.add("A");
l1.add("B");
List<Object> l2 = new ArrayList<Object>();
l2.add("dog");
l2.add("cat");
l1.add(l2);
data.add(l1);
data.add("3");
List<String> r0 = new ArrayList<String>();
rowList.add(r0);
System.out.println(data);
rowList = processData(r0, data, rowList);
System.out.println(rowList);
}

I think this should work for you if you're using Java 8:
List<Object> a = new ArrayList<>();
List<Object> a1 = new ArrayList<>();
a1.add("v");
a1.add("w");
List<Object> a2 = new ArrayList<>();
a2.add("ww");
a.add("a");
a.add("b");
a.add("c");
a.add("d");
a.add(a1);
a.add(a2);
List<Object> b = new ArrayList<>();
a.stream().flatMap(x -> x instanceof String ? Stream.of(x) : ((List) x).stream()).forEach(b::add);
System.out.println(a);
System.out.println(b);
b list will contain flattened a list. Output is:
[a, b, c, d, [v, w], [ww]]
[a, b, c, d, v, w, ww]

Related

error: incompatible types: List<Integer> cannot be converted to ArrayList<Integer>

I have found a few questions similar to the problem I am facing, but I couldn't find solution.
Example: Incompatible types List of List and ArrayList of ArrayList, Not able to understand how to define a List of List in java
The program should return list of lists. So, I declared a list of lists and then trying to add arraylists to it.
allsubsets = new ArrayList<List<Integer>>();
But, when I am trying to access each arraylist item from the list of lists as below, I get the error: incompatible types: List<Integer> cannot be converted to ArrayList<Integer>
for(ArrayList<Integer> subset:allsubsets)
When I try to convert the line to for(List<Integer> subset:allsubsets), it throws error that add, addAll don't exist for List type, which makes sense. Please help me understand how to access elements of list of lists in this case.
public List<List<Integer>> subsets(int[] nums) {
List<Integer> arrayList = new ArrayList<Integer>();
for(int i:nums) {
arrayList.add(i);
}
return subsets(arrayList,nums.length);
}
public List<List<Integer>> subsets(List<Integer> arrayList, int index) {
List<List<Integer>> allsubsets;
if(index == -1) {
allsubsets = new ArrayList<List<Integer>>();
allsubsets.add(new ArrayList<Integer>());
}
else {
allsubsets = subsets(arrayList, index-1);
int item = arrayList.get(index);
List<List<Integer>> moresubsets = new ArrayList<List<Integer>>();
for(ArrayList<Integer> subset:allsubsets) {
//The line above throws error as I created list of lists
List<Integer> newsubset = new ArrayList<Integer>(); //create new subset
newsubset.addAll(subset); // add all old items
newsubset.add(item); // add new item
moresubsets.add(newsubset); //add subset to moresubsets
}
allsubsets.add(moresubsets); // add to actual one
}
return allsubsets;
}
Note: If I change the return type to arraylist of arraylists, it works for me. But, I want to make it work for the list of lists
Correct way to iterate your list of list should be:
for(List<Integer> subset:allsubsets) {
instead of:
for(ArrayList<Integer> subset:allsubsets) {
List<List<Integer>> allsubsets is declared as List of List, but the implementation is unknown.
Only you know the type of nested List is ArrayList, so either change foreach to use List<Integer> or manually cast your List<Integer> to ArrayList<> (this is not preferred)
One more thing:
allsubsets.add(moresubsets); // add to actual one
This try to add a List of List (List<List<Integer>>) as element which should be List<Integer> hence compile error.
Change that statement to:
allsubsets.addAll(moresubsets);
Let's try expanding that enhanced for loop into more basic components:
for(ArrayList<Integer> subset:allsubsets) {
//The line above throws error as I created list of lists
}
// this is roughly equivalent to
Iterator<List<Integer>> it = allsubsets.iterator();
while(it.hasNext()) {
ArrayList<Integer> subset = it.next(); // Error
// Since the iterator was defined as an iterator to a List<List<Integer>>,
// it.next() will return the next element in allsubsets
// which happens to be an List<Integers>.
// You can't assign a reference of a parent type to a child. However
// the opposite is perfectly fine, assigning a reference of a child type
// to a parent.
// If we change subset to be a List<Integer> i.e.
// for(List<Integer> subset : allsubsets)
// then we are assigning a reference of a List<Integer> to a List<Integer>
// so no problem.
}
I prefer to share with you the code I did for managing the same type of Object List you are trying to handle. Hope this helps.
public static void main(String[] args) {
List<List<Integer>> allsubsets = setSubsets();
List<List<Integer>> allsubsets2 = new ArrayList<>();
allsubsets2.addAll(allsubsets);
int i= 0;
for (List<Integer> test : allsubsets2) {
System.out.println(i + " Lista");
for (Integer integer : test) {
System.out.println(integer);
}
i++;
}
}
public static List<List<Integer>> setSubsets() {
List<List<Integer>> allsubsets = new ArrayList<List<Integer>>();
List<Integer> listInteger1 = new ArrayList<>();
List<Integer> listInteger2 = new ArrayList<>();
for (int i = 0; i < 100; i++) {
listInteger1.add(i);
}
for (int i = 1010; i < 1110; i++) {
listInteger2.add(i);
}
allsubsets.add(listInteger1);
allsubsets.add(listInteger2);
return allsubsets;
}

Looping through different arrays lists

I have three different arrays of different sizes to gather node status and I would like to iterate through all of them with one loop instead of creating one for each. I've seen examples with naming the array as an integer and doing a while/for loop and incrementing, but I would like to find a method to keep the current array names. Here is what I have so far.
EDIT : I would like to keep all lists separate so that it is easily distinguishable what nodes have what status.. i.e.
Online - node1, node2 | Offline - node3, node4 | Unknown - node5, node6
private String nodeStatus() {
List<Node> onlineNodes = new ArrayList<Node>();
List<Node> offlineNodes = new ArrayList<Node>();
List<Node> unknownNodes = new ArrayList<Node>();
for(Node n : getNodes()){
if (n.isRunning() == RunningType.ONLINE) {
onlineNodes.add(n);
}
if (n.isRunning() == RunningType.OFFLINE) {
offlineNodes.add(n);
}
if (n.isRunning() == RunningType.UNKNOWN) {
unknownNodes.add(n);
}
}
for (Node element : <online,offline,unknown>) {
System.out.println(element);
}
}
If I understand correctly, what you want is to iterate through 3 lists on 1 for-loop w/o using a 4th list, the way you can achieve this is:
import java.util.*;
public class MultipleArraysLooping {
public static void main (String args[]) {
List <String> list1 = new ArrayList <String>();
List <String> list2 = new ArrayList <String>();
List <String> list3 = new ArrayList <String>();
fillLists(list1, list2, list3);
iterateLists(list1, list2, list3);
}
public static void fillLists(List <String> list1,
List <String> list2, List <String> list3) {
list1.add("item1 on list1");
list1.add("item2 on list1");
list1.add("item3 on list1");
list2.add("item1 on list2");
list2.add("item2 on list2");
list2.add("item3 on list2");
list2.add("item4 on list2");
list2.add("item5 on list2");
list3.add("item1 on list3");
list3.add("item2 on list3");
}
public static void iterateLists(List <String> list1,
List <String> list2, List <String> list3) {
int size = 0;
if (list1.size() > list2.size()) {
if (list1.size() > list3.size()) {
size = list1.size();
} else {
size = list3.size();
}
} else {
if (list2.size() > list3.size()) {
size = list2.size();
} else {
size = list3.size();
}
}
for (int i = 0; i < size; i++) {
if (i < list1.size()) {
System.out.println(list1.get(i));
}
if (i < list2.size()) {
System.out.println(list2.get(i));
}
if (i < list3.size()) {
System.out.println(list3.get(i));
}
}
}
}
The output given by the above code is:
item1 on list1
item1 on list2
item1 on list3
item2 on list1
item2 on list2
item2 on list3
item3 on list1
item3 on list2
item4 on list2
item5 on list2
As you can see, it iterates over each list alternatively
I hope this helps, probably there's a better way to get the largest size of the arrays.
If what you want is to iterate the 3 of them in order (list 1 complete, then list 2 and lastly list 3) or by some state, well, you need to add your logic there
You might want to keep a map of statuses to elements instead of having 3 separate variables. Assuming you have Java 8 and getNodes() returns a Collection, you can do something like this:
Map<String, List<Node>> elementsByStatus = getNodes().stream()
.collect(Collectors.groupingBy(Node::isRunning));
// print all elements
elementsByStatus.stream()
.flatMap(List::stream)
.forEach(System.out::println);
If you need to iterate over elements by status, you can do this:
elementsByStatus.forEach((status, elements) -> {
elements.forEach(element -> {
//...
});
});
You Can try by this:
public class ListIterator {
public static void print(List<String> list){
for (String string : list) {
System.out.println(string);
}
}
public static void main(String[] args) {
List<String> list1=new ArrayList<>();
List<String> list2=new ArrayList<>();
List<String> list3=new ArrayList<>();
list1.add("List11");
list1.add("List12");
list1.add("List14");
print(list1);
System.out.println();
list2.add("List21");
list2.add("List22");
print(list2);
System.out.println();
list3.add("List3");
print(list3);
System.out.println();
}
}
You can also try this:
public class ListIterator {
public static void print(List<String> list){
for (String string : list) {
System.out.println(string);
}
}
public static void main(String[] args) {
List<String> list1=new ArrayList<>();
List<String> list2=new ArrayList<>();
List<String> list3=new ArrayList<>();
list1.add("List11");
list1.add("List12");
list1.add("List13");
list2.add("B1");
list2.add("B2");
list3.add("C1");
int a=list1.size();
int b=list2.size();
int c=list3.size();
int max=Math.max(a, b);
max=Math.max(max, c);
//System.out.println("");
for(int i=0;i<max;i++){
if (i<list1.size()) {
System.out.println(list1.get(i));
}
if (i<list2.size()) {
System.out.println(list2.get(i));
}
if (i<list3.size()) {
System.out.println(list3.get(i));
}
}
}
}

Best way to create a tree from rowset in Java

Let's assume I have a list of lists in Java as follows:
[
[A, AA, 10],
[A, AB, 11],
[B, BA, 20],
[A, AA, 12],
]
I would like to process each row to create maps of maps, so that I can address the last value in each row as follows:
{
A: {
AA: [10, 12]
AB: [11]
},
B: {
BA: [20]
}
}
In this way I can do calls like:
for (int i : map.get("A").get("AA")) { ... }
Of course, I can iterate over the list and create the maps manually. However that is quite ugly piece of code and it is hard to generalize it for 3,4,5,...,n columns.
Is there some clever way of working with such lists? Some kind of library or something else I haven't thought about?
Yet another quite ugly piece of code :-)
class CustomTree {
private final Map store;
private final int length;
public CustomTree(List<List<String>> source, int length) {
if (length < 2)
throw new IllegalArgumentException("Length must be greater than 2");
this.length = length;
this.store = new HashMap();
for (int i = 0; i < source.size(); i++) {
List<String> line = source.get(i);
if (line.size() != length)
throw new IllegalArgumentException(String.format("Line %d has wrong length", i));
}
for (List<String> line : source) {
if (line.size() != length)
throw new IllegalArgumentException("Not all lines have right length");
accumulate(store, line);
}
}
public void accumulate(Map parent, List<String> keys) {
String key = keys.get(0);
Object value = parent.get(key);
if (keys.size() == 2) {
parent.put(key, value != null
? addToList((List) value, keys.get(1))
: addToList(new ArrayList(), keys.get(1)));
} else {
Map child;
if (value != null) {
child = (Map) value;
} else {
child = new HashMap();
parent.put(key, child);
}
accumulate(child, keys.subList(1, keys.size()));
}
}
private List addToList(List list, String key) {
Integer intValue = Integer.valueOf(key);
if (!list.contains(intValue))
list.add(intValue);
return list;
}
public List<Integer> get(List<String> keys) {
if (keys.size() != (length - 1))
throw new IllegalArgumentException("Bad keys length");
return get(keys, store);
}
private List<Integer> get(List<String> keys, Map tree) {
Object object = tree.get(keys.get(0));
if (object == null)
return new ArrayList<Integer>(0);
return keys.size() == 1
? ((List<Integer>) object)
: get(keys.subList(1, keys.size()), (Map) object);
}
}
Usage
public class Main {
public static void main(String[] args) {
List<List<String>> source = new ArrayList<List<String>>();
List<String> first = Arrays.asList("A", "AA", "CB", "10");
List<String> second = Arrays.asList("A", "AB", "CB", "11");
List<String> third = Arrays.asList("BA", "BA", "CB", "20");
List<String> fourth = Arrays.asList("A", "AA", "CB", "12");
List<String> fifth = Arrays.asList("BA", "BA", "CB", "21");
source.add(first);
source.add(second);
source.add(third);
source.add(fourth);
source.add(fifth);
CustomTree tree = new CustomTree(source, 4);
System.out.println(tree.get(Arrays.asList("BA", "BA", "CB")));
System.out.println(tree.get(Arrays.asList("BA", "B", "sf")));
}
}
May be too ugly. It works only if need a final element of tree without any intermediate Map.

How to search for a string in an arraylist

I want to search for a string in an arraylist.
My ArrayList contains:
ArrayList <String> list = new ArrayList();
list.add("behold");
list.add("bend");
list.add("bet");
list.add("bear");
list.add("beat");
list.add("become");
list.add("begin");
Now I want to search for "bea" and it should return a list containing "bear" and "beat".
How can I implement it?
List <String> list = new ArrayList();
list.add("behold");
list.add("bend");
list.add("bet");
list.add("bear");
list.add("beat");
list.add("become");
list.add("begin");
List <String> listClone = new ArrayList<String>();
for (String string : list) {
if(string.matches("(?i)(bea).*")){
listClone.add(string);
}
}
System.out.println(listClone);
Loop through your list and do a contains or startswith.
ArrayList<String> resList = new ArrayList<String>();
String searchString = "bea";
for (String curVal : list){
if (curVal.contains(searchString)){
resList.add(curVal);
}
}
You can wrap that in a method. The contains checks if its in the list. You could also go for startswith.
Nowadays, Java 8 allows for a one-line functional solution that is cleaner, faster, and a whole lot simpler than the accepted solution:
List<String> list = new ArrayList<>();
list.add("behold");
list.add("bend");
list.add("bet");
list.add("bear");
list.add("beat");
list.add("become");
list.add("begin");
List<String> matches = list.stream().filter(it -> it.contains("bea")).collect(Collectors.toList());
System.out.println(matches); // [bear, beat]
And even easier in Kotlin:
val matches = list.filter { it.contains("bea") }
May be easier using a java.util.HashSet. For example:
List <String> list = new ArrayList<String>();
list.add("behold");
list.add("bend");
list.add("bet");
//Load the list into a hashSet
Set<String> set = new HashSet<String>(list);
if (set.contains("bend"))
{
System.out.println("String found!");
}
Since your list doesn't appear to be sorted, you have to iterate over its elements. Apply startsWith() or contains() to each element, and store matches in an auxiliary list. Return the auxiliary list when done.
Better way is to use matches() method on every String element of the array. This will help you to search any pattern through regular expressions.
The Best Order I've seen :
// SearchList is your List
// TEXT is your Search Text
// SubList is your result
ArrayList<String> TempList = new ArrayList<String>(
(SearchList));
int temp = 0;
int num = 0;
ArrayList<String> SubList = new ArrayList<String>();
while (temp > -1) {
temp = TempList.indexOf(new Object() {
#Override
public boolean equals(Object obj) {
return obj.toString().startsWith(TEXT);
}
});
if (temp > -1) {
SubList.add(SearchList.get(temp + num++));
TempList.remove(temp);
}
}
First you have to copy, from AdapterArrayList to tempsearchnewArrayList ( Add ListView items into tempsearchnewArrayList ) , because then only you can compare whether search text is appears in Arraylist or not.
After creating temporary arraylist, add below code.
searchEditTextBox.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
String txt = charSequence.toString().trim();
int txtlength = txt.length();
if (txtlength > 0) {
AdapterArrayList = new ArrayList<HashMap<String, String>>();
for (int j = 0; j< tempsearchnewArrayList.size(); j++) {
if (tempsearchnewArrayList.get(j).get("type").toLowerCase().contains(txt)) {
AdapterArrayList.add(tempsearchnewArrayList.get(j));
}
}
} else {
AdapterArrayList = new ArrayList<HashMap<String, String>>();
AdapterArrayList.addAll(tempsearchnewArrayList);
}
adapter1.notifyDataSetChanged();
if (AdapterArrayList.size() > 0) {
mainactivitylistview.setAdapter(adapter1);
} else {
mainactivitylistview.setAdapter(null);
}
}
#Override
public void afterTextChanged(Editable editable) {
}
});
List <String> list = new ArrayList();
list.add("behold");
list.add("bend");
list.add("bet");
list.add("bear");
list.add("beat");
list.add("become");
list.add("begin");
List <String> listClone = new ArrayList<String>();
Pattern pattern = Pattern.compile("bea",Pattern.CASE_INSENSITIVE); //incase u r not concerned about upper/lower case
for (String string : list) {
if(pattern.matcher(string).find()) {
listClone.add(string);
continue;
}
}
System.out.println(listClone);
TRY using Google guava library
FOR MORE INFO --> https://github.com/google/guava
Iterable<String> result = Iterables.filter(yourListContainStringsYouWantToSearch, Predicates.containsPattern(search));
Log.i("resultsInList", "performSearch:\n"+ Lists.newArrayList(result.iterator()));
import java.util.*;
class ArrayLst
{
public static void main(String args[])
{
ArrayList<String> ar = new ArrayList<String>();
ar.add("pulak");
ar.add("sangeeta");
ar.add("sumit");
System.out.println("Enter the name:");
Scanner scan=new Scanner(System.in);
String st=scan.nextLine();
for(String lst: ar)
{
if(st.contains(lst))
{
System.out.println(st+"is here!");
break;
}
else
{
System.out.println("OOps search can't find!");
break;
}
}
}
}

Java join collections using functor

2 collections are given with the same number of elements, say List<String>. What are elegant ways in JAVA to apply a functor on each 2 elements of collections with corresponding indexes?
Say, one example could be:
List<String> = { "APPLE", "PEAR" };
List<String> = { "BANANA", "ORANGE" };
A predicate that joins string together will result in the following List<String>:
List<String> = { "APPLEBANANA", "PEARORANGE" };
Akin to the functors found in Apache Commons Collections, I have created binary equivalents in the past.
For your situation, a binary transformer type object, which takes to two input objects and returns a single object, could be used. Here is some sample code that's conveys my approach:
// tranformer
interface BinaryTransformer<X, Y, Z> {
Z transform(X a, Y b);
}
// implementation for your problem
class ConcatTransformer implements BinaryTransformer<String, String, String> {
public String transform(String a, String b) {
return a + b;
}
}
// general use transformer
class BinaryListUtils {
public static <X, Y, Z> List<Z> collect(List<X> aList, List<Y> bList, BinaryTransformer<X, Y, Z> t) {
List<Z> ret = new ArrayList<Z>(aList.size());
Iterator<X> aIter = aList.iterator();
Iterator<Y> bIter = bList.iterator();
while(aIter.hasNext()) {
ret.add(t.transform(aIter.next(), bIter.next()));
}
}
}
HTH
A quick driver of this showed it to work. Not responsible for all test cases. :-)
List<String> combineListsHorizontally(List<String> a, List<String> b) {
assert a.size() == b.size(); // just avoids some checks
List<String> result = new ArrayList<String>(a.size());
Iterator<String> itera = a.iterator();
Iterator<String> iterb = b.iterator();
for(int i = 0; i < a.size(); i++) {
String combined = itera.next() + iterb.next();
result.add(combined);
}
return result;
}
If you need something generic, you would need to know they ahve a way that they can be joined
List<E> combineListsHorizontally(List<E> a, List<E> b) {
assert a.size() == b.size(); // just avoids some checks
List<E> result = new ArrayList<E>(a.size());
Iterator<E> itera = a.iterator();
Iterator<E> iterb = b.iterator();
for(int i = 0; i < a.size(); i++) {
E combined = new MagicCombiner<E>(a,b).get(); // define this line yourself
result.add(combined);
}
return result;
}
///////////////// EDIT - here's a working example based off #Brents (superior) example. Props to him for illustrating this pattern better than I did.
import java.util.*;
/**
* Compile: "javac BinaryListUtils"
* Usage: "java BinaryListUtils"
C:\Documents and Settings\user\My Documents>javac BinaryListUtils.java
C:\Documents and Settings\user\My Documents>java BinaryListUtils
APPLEBANANA
PEARORANGE
C:\Documents and Settings\user\My Documents>
*/
// general use transformer
class BinaryListUtils {
// tranformer
static interface BinaryTransformer<X, Y, Z> {
Z transform(X a, Y b);
}
// implementation for your problem
static class ConcatTransformer implements BinaryTransformer<String, String, String> {
public String transform(String a, String b) {
return a + b;
}
}
public static <X, Y, Z> List<Z> collect(List<X> aList, List<Y> bList, BinaryTransformer<X, Y, Z> t) {
List<Z> ret = new ArrayList<Z>(aList.size());
Iterator<X> aIter = aList.iterator();
Iterator<Y> bIter = bList.iterator();
while(aIter.hasNext()) {
ret.add(t.transform(aIter.next(), bIter.next()));
}
return ret;
}
public static void main(String[] args) {
List<String> aList = new ArrayList<String>();
List<String> bList = new ArrayList<String>();
aList.add("APPLE");
aList.add("PEAR");
bList.add("BANANA");
bList.add("ORANGE");
ConcatTransformer ct = new ConcatTransformer();
List<String> cList = BinaryListUtils.collect(aList,bList,ct);
for(String s : cList) System.out.println(s);
}
}
What you're asking for isn't a predicate. It's doing a transformation on the lists zipped together. The generic way to do this is to write an iterable zipper that will zip the two lists into an iterable of a Pair, and then apply the transformation to the pairs.
I initially thought you were asking for the intersection of two collections, which is supplied in Guava collections as Sets.intersection(Set, Set).
I think your best bet here will be to do it iteratively. I can't think of any core Java API that can do it.
public List<String> predicate(List<String> list1, List<String> list2) {
List<String> list = new ArrayList<String>();
for(int i = 0; i < list1.size(); i++) {
list.add(new StringBuilder(list1.get(i)).append(list2.get(i)).toString());
}
return list;
}
Haven't compiled / run it. Good luck.

Categories

Resources