Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #33471 > unrolled thread

Stream FlatMap

Started byPhilipp Kraus <philipp.kraus.flashpixx@gmail.com>
First post2016-01-18 07:57 -0800
Last post2016-01-21 10:12 -0500
Articles 7 — 5 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  Stream FlatMap Philipp Kraus <philipp.kraus.flashpixx@gmail.com> - 2016-01-18 07:57 -0800
    Re: Stream FlatMap Sebastian <news@seyweiler.dyndns.org> - 2016-01-18 23:11 +0100
      Re: Stream FlatMap Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-01-18 18:18 -0500
    Re: Stream FlatMap Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-01-18 20:34 -0500
      Re: Stream FlatMap Sebastian <sebastian.millies@softwareag.com> - 2016-01-19 04:12 -0800
        Re: Stream FlatMap Philipp Kraus <philipp.kraus.flashpixx@gmail.com> - 2016-01-19 12:15 -0800
          Re: Stream FlatMap Arne Vajhøj <arne@vajhoej.dk> - 2016-01-21 10:12 -0500

#33471 — Stream FlatMap

FromPhilipp Kraus <philipp.kraus.flashpixx@gmail.com>
Date2016-01-18 07:57 -0800
SubjectStream FlatMap
Message-ID<39a5793c-6a65-4402-9c11-69667a03f11d@googlegroups.com>
Hello,

I have got a list like:

List<?> x = [1,2, [4,5, ["a", "b"], "c", "d"], ["x", "y"], "z"];

and I would like to flat this list into

y = [1, 2, 4, 5, "a", "b", "c", "d", "x", "y", "z"]

The list can store any object type so it can be a raw value or any collection typ (with recursion).
How can I flat this list with the streams?

Thanks

Phil

[toc] | [next] | [standalone]


#33473

FromSebastian <news@seyweiler.dyndns.org>
Date2016-01-18 23:11 +0100
Message-ID<n7jnv4$peu$1@news.albasani.net>
In reply to#33471
Am 18.01.2016 18:29, schrieb Stefan Ram:
> Philipp Kraus <philipp.kraus.flashpixx@gmail.com> writes:
>> List<?> x = [1,2, [4,5, ["a", "b"], "c", "d"], ["x", "y"], "z"];
>> and I would like to flat this list into
>
>    The verb is »to flatten«.
>
>    The code does not compile:
>
> Main.java:38: error: illegal start of expression
>      List<?> x = [1,2, [4,5, ["a", "b"], "c", "d"], ["x", "y"], "z"];
>                  ^
> 1 error
>

Well, obviously the OP didn't intend that as a list literal, since Java 
does not have them, but as shorthand in pseudo-code.

There's a solution at
http://rosettacode.org/wiki/Flatten_a_list#Java

It's ugly, does anyone see a way to avoid using instanceof?

-- Sebastian

[toc] | [prev] | [next] | [standalone]


#33474

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-01-18 18:18 -0500
Message-ID<n7jrn9$qc7$1@dont-email.me>
In reply to#33473
On 1/18/2016 5:11 PM, Sebastian wrote:
> Am 18.01.2016 18:29, schrieb Stefan Ram:
>> Philipp Kraus <philipp.kraus.flashpixx@gmail.com> writes:
>>> List<?> x = [1,2, [4,5, ["a", "b"], "c", "d"], ["x", "y"], "z"];
>>> and I would like to flat this list into
>>
>>    The verb is »to flatten«.
>>
>>    The code does not compile:
>>
>> Main.java:38: error: illegal start of expression
>>      List<?> x = [1,2, [4,5, ["a", "b"], "c", "d"], ["x", "y"], "z"];
>>                  ^
>> 1 error
>>
>
> Well, obviously the OP didn't intend that as a list literal, since Java
> does not have them, but as shorthand in pseudo-code.
>
> There's a solution at
> http://rosettacode.org/wiki/Flatten_a_list#Java
>
> It's ugly, does anyone see a way to avoid using instanceof?

     Since he needs to distinguish between "atoms" and things that
need to be flattened recursively, `instanceof' (or a reflective
equivalent) seems unavoidable.

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#33477

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-01-18 20:34 -0500
Message-ID<n7k3mr$6pq$1@dont-email.me>
In reply to#33471
On 1/18/2016 10:57 AM, Philipp Kraus wrote:
> Hello,
>
> I have got a list like:
>
> List<?> x = [1,2, [4,5, ["a", "b"], "c", "d"], ["x", "y"], "z"];
>
> and I would like to flat this list into
>
> y = [1, 2, 4, 5, "a", "b", "c", "d", "x", "y", "z"]
>
> The list can store any object type so it can be a raw value or any collection typ (with recursion).
> How can I flat this list with the streams?

     Got it!!!

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Foo {

    public static Stream<Object> flatten(Object thing) {
       return (thing instanceof List)
             ? ((List<Object>) thing).stream().flatMap((item) -> 
flatten(item))
             : Stream.of(thing);
    }

    public static void main(String[] unused) {
       List<?> list = Arrays.asList(
             1,
             2,
             Arrays.asList(
                   4,
                   5,
                   Arrays.asList("a", "b"),
                   "c",
                   "d"
             ),
             Arrays.asList("x", "y"),
             "z"
       );

       System.out.println(list);
       System.out.println();
       List<?> flattened = flatten(list).collect(Collectors.toList());
       System.out.println(flattened);
    }
}

-- 
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM

[toc] | [prev] | [next] | [standalone]


#33478

FromSebastian <sebastian.millies@softwareag.com>
Date2016-01-19 04:12 -0800
Message-ID<a3a0221a-a5e6-4e0d-9018-4aa770e3eeb5@googlegroups.com>
In reply to#33477
Am Dienstag, 19. Januar 2016 02:35:11 UTC+1 schrieb Eric Sosman:
> On 1/18/2016 10:57 AM, Philipp Kraus wrote:
> > Hello,
> >
> > I have got a list like:
> >
> > List<?> x = [1,2, [4,5, ["a", "b"], "c", "d"], ["x", "y"], "z"];
> >
> > and I would like to flat this list into
> >
> > y = [1, 2, 4, 5, "a", "b", "c", "d", "x", "y", "z"]
> >
> > The list can store any object type so it can be a raw value or any collection typ (with recursion).
> > How can I flat this list with the streams?
> 
>      Got it!!!
> 
> import java.util.Arrays;
> import java.util.List;
> import java.util.stream.Collectors;
> import java.util.stream.Stream;
> 
> public class Foo {
> 
>     public static Stream<Object> flatten(Object thing) {
>        return (thing instanceof List)
>              ? ((List<Object>) thing).stream().flatMap((item) -> 
> flatten(item))
>              : Stream.of(thing);
>     }
> 
>     public static void main(String[] unused) {
>        List<?> list = Arrays.asList(
>              1,
>              2,
>              Arrays.asList(
>                    4,
>                    5,
>                    Arrays.asList("a", "b"),
>                    "c",
>                    "d"
>              ),
>              Arrays.asList("x", "y"),
>              "z"
>        );
> 
>        System.out.println(list);
>        System.out.println();
>        List<?> flattened = flatten(list).collect(Collectors.toList());
>        System.out.println(flattened);
>     }
> }
> 
> -- 
> esosman@comcast-dot-net.invalid
> "Don't be afraid of work. Make work afraid of you." -- TLM

Yes, that's a variant of the Rosetta solution: There solution differs from yours by having List in the signature and the instanceof check inside the flatMap. I like that better, because the signature already announces that only Lists can be flattened.

Here's a non-recursive solution that pushes the nested elements onto a stack:

public List<?> flattenNonRecursive(List<?> list) {
  List<Object> flattened = new ArrayList<>();
  Stack<Object> stack = new Stack<>();
  stack.pushAll(list);
  while (!stack.isEmpty()) {
    Object item = stack.pop();
    if (item instanceof List<?>) 
      stack.pushAll((List<?>) item);
    else 
      flattened.add(item);
  }
  return flattened;
}

static class Stack<T> extends ArrayDeque<T> {
  void pushAll(List<? extends T> ts) {
    ListIterator<? extends T> listIter = ts.listIterator(ts.size());
    while(listIter.hasPrevious()){
      push(listIter.previous());
    }
  }
}
  
-- Sebastian

[toc] | [prev] | [next] | [standalone]


#33480

FromPhilipp Kraus <philipp.kraus.flashpixx@gmail.com>
Date2016-01-19 12:15 -0800
Message-ID<a9c0a5df-cfab-4bf0-90bb-c99d9573a72c@googlegroups.com>
In reply to#33478
> Yes, that's a variant of the Rosetta solution: There solution differs from yours by having List in the signature and the instanceof check inside the flatMap. I like that better, because the signature already announces that only Lists can be flattened.

Thanks for the code excerpt. I have modified this code:
	
public static Stream<Object> flattenToStream(List<?> list) {
		return list.stream().flatMap(item ->
			item instanceof List<?> ?
			flattenToStream((List<?>)item) :
			Stream.of(item));
	}

for my system, so it works well with my term, atom structure :-)

Phil

[toc] | [prev] | [next] | [standalone]


#33497

FromArne Vajhøj <arne@vajhoej.dk>
Date2016-01-21 10:12 -0500
Message-ID<n7qshb$pp1$1@gioia.aioe.org>
In reply to#33480
On 1/19/2016 3:15 PM, Philipp Kraus wrote:
> Thanks for the code excerpt. I have modified this code:
> 	
> public static Stream<Object> flattenToStream(List<?> list) {
> 		return list.stream().flatMap(item ->
> 			item instanceof List<?> ?
> 			flattenToStream((List<?>)item) :
> 			Stream.of(item));
> 	}
>
> for my system, so it works well with my term, atom structure :-)

Given the data structure then this is more or less how to do it.

There are a couple of variations.

I would do it like:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class SimpleFlatten {
     public static Stream<?> flatten(Object o) {
         return (o instanceof Collection<?>) ? 
((Collection<?>)o).stream().flatMap(elm -> flatten(elm)) :
                (o instanceof Object[]) ? 
Arrays.stream((Object[])o).flatMap(elm -> flatten(elm)) :
                Stream.of(o);
     }
     public static void main(String[] args) {
         List<Object> all = new ArrayList<>();
         all.add(1);
         all.add("A");
         List<Object> sublist = new ArrayList<>();
         sublist.add(2);
         sublist.add("B");
         all.add(sublist);
         List<Object> innerlist = new ArrayList<>();
         innerlist.add(4);
         Object[] subarray = new Object[] { 3, "C",  innerlist };
         all.add(subarray);
         System.out.println(flatten(all).collect(Collectors.toList()));
     }
}

But that is just me.

If you want to avoid the instanceof, then you will need to change the
data structure.

Example:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class OOFlatten {
	public static abstract class Wrapper {
		public abstract Stream<?> stream();
	}
	public static class ObjectWrapper extends Wrapper {
		private Object v;
		public ObjectWrapper(Object v) {
			this.v = v;
		}
		@Override
		public Stream<?> stream() {
			return Stream.of(v);
		}
	}
	public static class CollectionWrapper extends Wrapper {
		private Collection<Wrapper> v;
		public CollectionWrapper(Collection<Wrapper> v) {
			this.v = v;
		}
		@Override
		public Stream<?> stream() {
			return v.stream().flatMap(o -> o.stream());
		}
	}
	public static class ArrayWrapper extends Wrapper {
		private Wrapper[] v;
		public ArrayWrapper(Wrapper[] v) {
			this.v = v;
		}
		@Override
		public Stream<?> stream() {
			return Arrays.stream(v).flatMap(o -> o.stream());
		}
	}
	public static Stream<?> flatten(Wrapper o) {
		return o.stream();
	}
	public static void main(String[] args) {
         List<Wrapper> all = new ArrayList<>();
         all.add(new ObjectWrapper(1));
         all.add(new ObjectWrapper("A"));
         List<Wrapper> sublist = new ArrayList<>();
         sublist.add(new ObjectWrapper(2));
         sublist.add(new ObjectWrapper("B"));
         all.add(new CollectionWrapper(sublist));
         List<Wrapper> innerlist = new ArrayList<>();
         innerlist.add(new ObjectWrapper(4));
         Wrapper[] subarray = new Wrapper[] { new ObjectWrapper(3), new 
ObjectWrapper("C"), new CollectionWrapper(innerlist) };
         all.add(new ArrayWrapper(subarray));
         System.out.println(flatten(new 
CollectionWrapper(all)).collect(Collectors.toList()));
	}
}

Arne



[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web