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


Groups > comp.lang.java.programmer > #38550

Re: Is there a better way to group and sort objects?

From Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid>
Newsgroups comp.lang.java.programmer
Subject Re: Is there a better way to group and sort objects?
Date 2018-08-09 16:06 +0200
Organization A noiseless patient Spider
Message-ID <pkhhsd$mgd$1@dont-email.me> (permalink)
References <8c045ff4-98c5-4253-9136-b26b34cf8f77@googlegroups.com>

Show all headers | View raw


On 2018-08-07 15:00, Eric Douglas wrote:
> I want to combine and sort objects by key properties and merge their secondary properties.  Is there a better way?  This is what I came up with..

<snip />

I was bored, so here's some code. Omitted imports and most of the
argument and null checks. Also, you might need Java 9 to run it.

public class ScratchPad {

    private static final class GroupBy<T, P> {
        private final String name;
        private final Function<T, P> extractor;
        private final BinaryOperator<P> accumulatorFunction;
        private final Supplier<P> initialValueSupplier;

        public GroupBy( String name, Function<T, P> extractor,
BinaryOperator<P> accumulatorFunction, Supplier<P> initialValueSupplier ) {
            this.name = name;
            this.extractor = extractor;
            this.accumulatorFunction = accumulatorFunction;
            this.initialValueSupplier = initialValueSupplier;
        }

        public GroupBy( String name, Function<T, P> extractor,
BinaryOperator<P> accumulatorFunction ) {
            this( name, extractor, accumulatorFunction, null );
        }

        public String name(){ return name; }

        public Function<T, P> extractor() {
            return extractor;
        }

        public BinaryOperator<P> accumulatorFunction() {
            return accumulatorFunction;
        }

        public Accumulator<T, P> newAccumulator(){
            return new Accumulator<>(
                this,
                initialValueSupplier == null ? null :
initialValueSupplier.get()
            );
        }
    }

    private static final class Accumulator<T, P> {

        private final GroupBy<T, P> groupBy;
        private P accumulation;

        public Accumulator( GroupBy<T, P> groupBy ) {
            this.groupBy = groupBy;
        }

        public Accumulator( GroupBy<T, P> groupBy, P initialValue ) {
            this( groupBy );
            accumulation = initialValue;
        }

        public String groupByName(){ return groupBy.name(); }

        public P accumulation(){ return accumulation; }

        public P accumulate( T t ){
            P newVal = groupBy.extractor().apply(t);
            return accumulation = accumulation == null ? newVal :
groupBy.accumulatorFunction().apply( accumulation, newVal );
        }
    }

    private static final class GroupAndSort<T, K extends Comparable<K>> {

        private final Function<T, K> keyExtractor;
        private final List<GroupBy<T, ?>> merged;

        private final SortedMap<K, List<Accumulator<T, ?>>>
            sieve = new TreeMap<>()
        ;

        @SafeVarargs
        public static <T, K extends Comparable<K>> GroupAndSort<T, K>
newInstance(
            Class<T> itemClass, Function<T, K> keyExtractor, GroupBy<T,
?>... merges
        ){
            return new GroupAndSort<>( keyExtractor, List.of( merges ) );
        }

        public GroupAndSort( Function<T, K> keyExtractor,
Collection<GroupBy<T, ?>> merges ){
            this.keyExtractor = keyExtractor;

            List<GroupBy<T, ?>> accs = new ArrayList<>();

            accs.add(
                new GroupBy<T, List<T>>(
                    null,
                    List::of,
                    (old, niou) -> {
                        old.addAll( niou );
                        return old;
                    },
                    ArrayList::new
                )
            );

            Set<String> groupNames = new HashSet<>();
            for( GroupBy<?, ?> g: merges ){
                if( g.name() == null ){
                    throw new IllegalArgumentException( "null groupBy
name: " + g );
                }
                if( ! groupNames.add(g.name()) ){
                    throw new IllegalArgumentException( "Duplicate
groupBy name: " + g.name() );
                }
            }

            accs.addAll( merges );

            this.merged = List.copyOf( accs );
        }

        public void put( T item ){
            K key = keyExtractor.apply( item );

            sieve.compute(
                key,
                (k, list) -> {
                    if( list == null ){
                        list = merged.stream().map(
GroupBy::newAccumulator ).collect(Collectors.toList());
                    }

                    list.forEach( acc -> acc.accumulate(item) );

                    return list;
                }
            );
        }

        @SafeVarargs
        public final void putAll( T... items ){
            for( T item: items ) this.put( item );
        }

        public Stream<K> keys(){
            return sieve.keySet().stream();
        }

        @SuppressWarnings( "unchecked" )
        public Stream<T> items(){
            return sieve.values().stream().flatMap( (l) ->
((Collection<T>)l.get(0).accumulation()).stream() );
        }

        @SuppressWarnings( "unchecked" )
        public Stream<T> items( K key ){
            List<Accumulator<T, ?>> props = sieve.get( key );

            if( props == null ){
                return Stream.empty();
            }
            else {
                return
((Collection<T>)props.get(0).accumulation()).stream();
            }

        }

        public List<?> mergedPropertiesFor( K key ){
            List<Accumulator<T, ?>> props = sieve.get( key );

            if( props == null ){
                return Collections.emptyList();
            }
            else {
                return props.stream().skip(1).map(
Accumulator::accumulation ).collect(Collectors.toList());
            }
        }

        public Map<String, ?> mergedPropertyMapFor( K key ){
            List<Accumulator<T, ?>> props = sieve.get( key );

            if( props == null ){
                return null;
            }
            else {
                return props.stream().skip(1).collect(
                    Collectors.toMap( Accumulator::groupByName,
Accumulator::accumulation )
                );
            }
        }
    }

    private static final class TestObject {

        private final String id;
        private final int sortingKey;
        private final int intProperty;
        private final boolean boolProperty;

        public TestObject( String id, int sortingKey, int intProperty,
boolean boolProperty ) {
            this.id = id;
            this.sortingKey = sortingKey;
            this.intProperty = intProperty;
            this.boolProperty = boolProperty;
        }

        public String id(){ return id; }

        public int sortingKey() {
            return sortingKey;
        }

        public int someIntProperty() {
            return intProperty;
        }

        public boolean someBoolProperty() {
            return boolProperty;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder( "TestObject{" );
            sb.append( "id='" ).append( id ).append( '\'' );
            sb.append( ", sortingKey=" ).append( sortingKey );
            sb.append( ", intProperty=" ).append( intProperty );
            sb.append( ", boolProperty=" ).append( boolProperty );
            sb.append( '}' );
            return sb.toString();
        }
    }


    public static void main( String[] ss ){
        TestObject t1 = new TestObject( "t1", 1, 34907, true );
        TestObject t2 = new TestObject( "t2", 1, 4, false );
        TestObject t3 = new TestObject( "t3", 10, 1, true );
        TestObject t4 = new TestObject( "t4", 4, 8, false );

        GroupAndSort<TestObject, Integer> group = GroupAndSort.newInstance(
            TestObject.class,
            TestObject::sortingKey,
            new GroupBy<>( "intProperty", TestObject::someIntProperty,
Integer::sum ),
            new GroupBy<>( "boolProperty", TestObject::someBoolProperty,
Boolean::logicalAnd )
        );

        group.putAll( t1, t3, t4, t2 );

        System.err.println( "Items: " +
group.items().collect(Collectors.toList()) );
        System.err.println( "Keys: " +
group.keys().collect(Collectors.toList()) );

        System.err.println( "Grouped items:" );
        group.keys().forEach(
            key -> System.err.printf( "%s -> %s%n", key,
group.items(key).collect(Collectors.toList()) )
        );

        System.err.println( "Merged properties:" );
        group.keys().forEach(
            key -> System.err.printf( "%s -> %s%n", key,
group.mergedPropertiesFor( key ) )
        );

        System.err.println( "Merged property maps:" );
        group.keys().forEach(
            key -> System.err.printf( "%s -> %s%n", key,
group.mergedPropertyMapFor( key ) )
        );
    }


}

Back to comp.lang.java.programmer | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-07 06:00 -0700
  Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 09:44 -0400
    Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 11:33 -0400
    Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-07 10:22 -0700
      Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 14:16 -0400
        Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 14:36 -0400
        Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-07 12:13 -0700
          Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-07 16:00 -0400
  Re: Is there a better way to group and sort objects? Martin Gregorie <martin@mydomain.invalid> - 2018-08-08 08:20 +0000
    Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-08 06:57 -0400
      Re: Is there a better way to group and sort objects? Martin Gregorie <martin@mydomain.invalid> - 2018-08-08 11:08 +0000
      Re: Is there a better way to group and sort objects? Martin Gregorie <martin@mydomain.invalid> - 2018-08-08 11:22 +0000
        Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-08 07:45 -0400
          Re: Is there a better way to group and sort objects? Martin Gregorie <martin@mydomain.invalid> - 2018-08-08 14:12 +0000
        Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-08 05:50 -0700
          Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-08 09:23 -0400
            Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-08 06:47 -0700
              Re: Is there a better way to group and sort objects? Eric Sosman <esosman@comcast-dot-net.invalid> - 2018-08-08 10:31 -0400
                Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-08 08:24 -0700
          Re: Is there a better way to group and sort objects? Robert Klemme <shortcutter@googlemail.com> - 2018-08-14 14:06 +0200
            Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-14 05:49 -0700
  Re: Is there a better way to group and sort objects? Daniele Futtorovic <da.futt.news@laposte-dot-net.invalid> - 2018-08-09 16:06 +0200
    Re: Is there a better way to group and sort objects? Eric Douglas <e.d.programmer@gmail.com> - 2018-08-14 05:47 -0700

csiph-web