This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/master by this push:
     new 40b012ce9b GROOVY-11351: Add zip and columns extension methods
40b012ce9b is described below

commit 40b012ce9b84ec8ba1864a21e9319fe2cc084358
Author: Paul King <pa...@asert.com.au>
AuthorDate: Thu Mar 28 12:57:20 2024 +1000

    GROOVY-11351: Add zip and columns extension methods
---
 .../groovy/runtime/ArrayGroovyMethods.java         | 136 +++++++++++++++++++++
 .../groovy/runtime/DefaultGroovyMethods.java       |  65 ++++++++++
 .../util/DoubleDoubleArrayColumnIterator.java      |  69 +++++++++++
 .../groovy/util/FloatFloatArrayColumnIterator.java |  69 +++++++++++
 .../groovy/util/IntIntArrayColumnIterator.java     |  69 +++++++++++
 .../groovy/util/LongLongArrayColumnIterator.java   |  69 +++++++++++
 6 files changed, 477 insertions(+)

diff --git a/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java 
b/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
index d3b7b9f96d..acf07d62ce 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
@@ -26,6 +26,7 @@ import groovy.lang.MetaClass;
 import groovy.lang.ObjectRange;
 import groovy.lang.Range;
 import groovy.lang.SpreadMap;
+import groovy.lang.Tuple2;
 import groovy.transform.stc.ClosureParams;
 import groovy.transform.stc.FirstParam;
 import groovy.transform.stc.FromString;
@@ -46,11 +47,15 @@ import org.codehaus.groovy.util.ByteArrayIterator;
 import org.codehaus.groovy.util.CharArrayIterator;
 import org.codehaus.groovy.util.DoubleArrayIterable;
 import org.codehaus.groovy.util.DoubleArrayIterator;
+import org.codehaus.groovy.util.DoubleDoubleArrayColumnIterator;
 import org.codehaus.groovy.util.FloatArrayIterator;
+import org.codehaus.groovy.util.FloatFloatArrayColumnIterator;
 import org.codehaus.groovy.util.IntArrayIterable;
 import org.codehaus.groovy.util.IntArrayIterator;
+import org.codehaus.groovy.util.IntIntArrayColumnIterator;
 import org.codehaus.groovy.util.LongArrayIterable;
 import org.codehaus.groovy.util.LongArrayIterator;
+import org.codehaus.groovy.util.LongLongArrayColumnIterator;
 import org.codehaus.groovy.util.ShortArrayIterator;
 
 import java.lang.reflect.Array;
@@ -75,6 +80,7 @@ import java.util.function.Consumer;
 import java.util.function.DoubleConsumer;
 import java.util.function.DoubleUnaryOperator;
 import java.util.function.Function;
+import java.util.function.IntBinaryOperator;
 import java.util.function.IntConsumer;
 import java.util.function.IntUnaryOperator;
 import java.util.function.LongConsumer;
@@ -1076,6 +1082,67 @@ public class ArrayGroovyMethods extends 
DefaultGroovyMethodsSupport {
         return DefaultGroovyMethods.collectMany(new ArrayIterable<>(self), 
collector, projection);
     }
 
+    
//--------------------------------------------------------------------------
+    // columns
+
+    /**
+     * An iterator of the columns of the array.
+     * <pre class="groovyTestCase">
+     * double[][] nums = [[1.0d, 2.0d], [10.0d, 20.0d]]
+     * assert nums.transpose() == nums.columns().toList()
+     * </pre>
+     *
+     * @param self a double[][]
+     * @return the iterator
+     */
+    public static Iterator<double[]> columns(double[][] self) {
+        return new DoubleDoubleArrayColumnIterator(self);
+    }
+
+    /**
+     * An iterator of the columns of the array.
+     * <pre class="groovyTestCase">
+     * float[][] nums = [[1.0f, 2.0f], [10.0f, 20.0f]]
+     * assert nums.transpose() == nums.columns().toList()
+     * </pre>
+     *
+     * @param self a float[][]
+     * @return the iterator
+     */
+    public static Iterator<float[]> columns(float[][] self) {
+        return new FloatFloatArrayColumnIterator(self);
+    }
+
+    /**
+     * An iterator of the columns of the array.
+     * <pre class="groovyTestCase">
+     * int[][] nums = [[1, 2], [10, 20]]
+     * assert nums.transpose() == nums.columns().toList()
+     * assert nums.columns().collect{ int[] col -> col.sum() } == [11, 22]
+     * </pre>
+     *
+     * @param self an int[][]
+     * @return the iterator
+     */
+    public static Iterator<int[]> columns(int[][] self) {
+        return new IntIntArrayColumnIterator(self);
+    }
+
+    /**
+     * An iterator of the columns of the array.
+     * <pre class="groovyTestCase">
+     * long[][] nums = [[1L, 2L], [10L, 20L]]
+     * assert nums.transpose() == nums.columns().toList()
+     * assert nums.columns().collect{ long[] col -> col.sum() } == [11L, 22L]
+     * </pre>
+     *
+     * @param self a long[][]
+     * @return the iterator
+     */
+    public static Iterator<long[]> columns(long[][] self) {
+        return new LongLongArrayColumnIterator(self);
+    }
+
     
//--------------------------------------------------------------------------
     // contains
 
@@ -8800,6 +8867,75 @@ public class ArrayGroovyMethods extends 
DefaultGroovyMethodsSupport {
         return DefaultGroovyMethods.collectEntries(new ArrayIterator<>(keys), 
collector, Function.identity(), valueTransform);
     }
 
+    
//--------------------------------------------------------------------------
+    // zip
+
+    /**
+     * An iterator of all the pairs of two arrays.
+     * <pre class="groovyTestCase">
+     * double[] small = [1.0d, 2.0d, 3.0d]
+     * double[] large = [100d, 200d, 300d]
+     * assert [small, large].transpose() == small.zip(large).toList()
+     * </pre>
+     *
+     * @param self a double[]
+     * @param other another double[]
+     * @return an iterator of all the pairs from self and other
+     */
+    public static Iterator<Tuple2<Double, Double>> zip(double[] self, double[] 
other) {
+        return DefaultGroovyMethods.zip(new DoubleArrayIterator(self), new 
DoubleArrayIterator(other));
+    }
+
+    /**
+     * An iterator of all the pairs of two arrays.
+     * <pre class="groovyTestCase">
+     * float[] small = [1.0f, 2.0f, 3.0f]
+     * float[] large = [100f, 200f, 300f]
+     * assert [small, large].transpose() == small.zip(large).toList()
+     * </pre>
+     *
+     * @param self a float[]
+     * @param other another float[]
+     * @return an iterator of all the pairs from self and other
+     */
+    public static Iterator<Tuple2<Float, Float>> zip(float[] self, float[] 
other) {
+        return DefaultGroovyMethods.zip(new FloatArrayIterator(self), new 
FloatArrayIterator(other));
+    }
+
+    /**
+     * An iterator of all the pairs of two arrays.
+     * <pre class="groovyTestCase">
+     * int[] small = [1, 2, 3]
+     * int[] large = [100, 200, 300]
+     * assert [101, 202, 303] == small.zip(large).collect{ a, b -> a + b }
+     * assert [small, large].transpose() == small.zip(large).toList()
+     * </pre>
+     *
+     * @param self an int[]
+     * @param other another int[]
+     * @return an iterator of all the pairs from self and other
+     */
+    public static Iterator<Tuple2<Integer, Integer>> zip(int[] self, int[] 
other) {
+        return DefaultGroovyMethods.zip(new IntArrayIterator(self), new 
IntArrayIterator(other));
+    }
+
+    /**
+     * An iterator of all the pairs of two arrays.
+     * <pre class="groovyTestCase">
+     * long[] small = [1L, 2L, 3L]
+     * long[] large = [100L, 200L, 300L]
+     * assert [101L, 202L, 303L] == small.zip(large).collect{ a, b -> a + b }
+     * assert [small, large].transpose() == small.zip(large).toList()
+     * </pre>
+     *
+     * @param self a long[]
+     * @param other another long[]
+     * @return an iterator of all the pairs from self and other
+     */
+    public static Iterator<Tuple2<Long, Long>> zip(long[] self, long[] other) {
+        return DefaultGroovyMethods.zip(new LongArrayIterator(self), new 
LongArrayIterator(other));
+    }
+
     
//--------------------------------------------------------------------------
 
     /**
diff --git 
a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java 
b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index e2ed576897..cd366b4e15 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -15885,6 +15885,71 @@ public class DefaultGroovyMethods extends 
DefaultGroovyMethodsSupport {
         }
     }
 
+    
//--------------------------------------------------------------------------
+    // zip
+
+    /**
+     * An iterator of all the pairs of two Iterables.
+     * <pre class="groovyTestCase">
+     * def one = ['cat', 'spider']
+     * def two = ['fish', 'monkey']
+     * assert ['catfish', 'spidermonkey'] == one.zip(two).collect{ a, b -> a + 
b }
+     * assert [one, two].transpose() == one.zip(two).toList()
+     * </pre>
+     *
+     * @param self an Iterable
+     * @param other another Iterable
+     * @return an iterator of all the pairs from self and other
+     * @since 5.0.0
+     */
+    public static <U, V> Iterator<Tuple2<U, V>> zip(Iterable<U> self, 
Iterable<V> other) {
+        return zip(self.iterator(), other.iterator());
+    }
+
+    /**
+     * An iterator of all the pairs of two Iterators.
+     * <pre class="groovyTestCase">
+     * def small = [1, 2, 3].iterator()
+     * def large = [100, 200, 300].iterator()
+     * assert [101, 202, 303] == small.zip(large).collect{ a, b -> a + b }
+     * assert [small.toList(), large.toList()].transpose() == 
small.zip(large).toList()
+     * </pre>
+     *
+     * @param self an Iterator
+     * @param other another Iterator
+     * @return an iterator of all the pairs from self and other
+     * @since 5.0.0
+     */
+    public static <U, V> Iterator<Tuple2<U, V>> zip(Iterator<U> self, 
Iterator<V> other) {
+        return new ZipIterator<>(self, other);
+    }
+
+    private static final class ZipIterator<U, V> implements Iterator<Tuple2<U, 
V>> {
+        private final Iterator<U> delegate;
+        private final Iterator<V> other;
+
+        private ZipIterator(Iterator<U> delegate, Iterator<V> other) {
+            this.delegate = delegate;
+            this.other = other;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return delegate.hasNext() && other.hasNext();
+        }
+
+        @Override
+        public Tuple2<U, V> next() {
+            if (!hasNext()) throw new NoSuchElementException();
+            return new Tuple2<>(delegate.next(), other.next());
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
     
//--------------------------------------------------------------------------
     // withTraits
 
diff --git 
a/src/main/java/org/codehaus/groovy/util/DoubleDoubleArrayColumnIterator.java 
b/src/main/java/org/codehaus/groovy/util/DoubleDoubleArrayColumnIterator.java
new file mode 100644
index 0000000000..e6b313a025
--- /dev/null
+++ 
b/src/main/java/org/codehaus/groovy/util/DoubleDoubleArrayColumnIterator.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * An iterator providing the columns of a double[][].
+ * In the case of an array with different size rows,
+ * the number of columns will be equal to the length of the smallest row.
+ *
+ * @since 5.0.0
+ */
+public class DoubleDoubleArrayColumnIterator implements Iterator<double[]> {
+    private final double[][] array;
+    private int columnIndex = 0;
+    private int numColumns;
+
+    public DoubleDoubleArrayColumnIterator(final double[][] array) {
+        Objects.requireNonNull(array);
+        this.array = array;
+        numColumns = Integer.MAX_VALUE;
+        for (double[] row: array) {
+            if (row.length < numColumns) numColumns = row.length;
+        }
+        if (numColumns == Integer.MAX_VALUE) numColumns = 0;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return columnIndex < numColumns;
+    }
+
+    @Override
+    public double[] next() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        double[] col = new double[array.length];
+        for (int r = 0; r < array.length; r++) {
+            col[r] = array[r][columnIndex];
+        }
+        columnIndex++;
+        return col;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("Remove not supported for 
arrays");
+    }
+}
diff --git 
a/src/main/java/org/codehaus/groovy/util/FloatFloatArrayColumnIterator.java 
b/src/main/java/org/codehaus/groovy/util/FloatFloatArrayColumnIterator.java
new file mode 100644
index 0000000000..62e343bd8a
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/util/FloatFloatArrayColumnIterator.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * An iterator providing the columns of a float[][].
+ * In the case of an array with different size rows,
+ * the number of columns will be equal to the length of the smallest row.
+ *
+ * @since 5.0.0
+ */
+public class FloatFloatArrayColumnIterator implements Iterator<float[]> {
+    private final float[][] array;
+    private int columnIndex = 0;
+    private int numColumns;
+
+    public FloatFloatArrayColumnIterator(final float[][] array) {
+        Objects.requireNonNull(array);
+        this.array = array;
+        numColumns = Integer.MAX_VALUE;
+        for (float[] row: array) {
+            if (row.length < numColumns) numColumns = row.length;
+        }
+        if (numColumns == Integer.MAX_VALUE) numColumns = 0;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return columnIndex < numColumns;
+    }
+
+    @Override
+    public float[] next() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        float[] col = new float[array.length];
+        for (int r = 0; r < array.length; r++) {
+            col[r] = array[r][columnIndex];
+        }
+        columnIndex++;
+        return col;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("Remove not supported for 
arrays");
+    }
+}
diff --git 
a/src/main/java/org/codehaus/groovy/util/IntIntArrayColumnIterator.java 
b/src/main/java/org/codehaus/groovy/util/IntIntArrayColumnIterator.java
new file mode 100644
index 0000000000..53e3de1a90
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/util/IntIntArrayColumnIterator.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * An iterator providing the columns of an int[][].
+ * In the case of an array with different size rows,
+ * the number of columns will be equal to the length of the smallest row.
+ *
+ * @since 5.0.0
+ */
+public class IntIntArrayColumnIterator implements Iterator<int[]> {
+    private final int[][] array;
+    private int columnIndex = 0;
+    private int numColumns;
+
+    public IntIntArrayColumnIterator(final int[][] array) {
+        Objects.requireNonNull(array);
+        this.array = array;
+        numColumns = Integer.MAX_VALUE;
+        for (int[] row: array) {
+            if (row.length < numColumns) numColumns = row.length;
+        }
+        if (numColumns == Integer.MAX_VALUE) numColumns = 0;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return columnIndex < numColumns;
+    }
+
+    @Override
+    public int[] next() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        int[] col = new int[array.length];
+        for (int r = 0; r < array.length; r++) {
+            col[r] = array[r][columnIndex];
+        }
+        columnIndex++;
+        return col;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("Remove not supported for 
arrays");
+    }
+}
diff --git 
a/src/main/java/org/codehaus/groovy/util/LongLongArrayColumnIterator.java 
b/src/main/java/org/codehaus/groovy/util/LongLongArrayColumnIterator.java
new file mode 100644
index 0000000000..3e9aa245e9
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/util/LongLongArrayColumnIterator.java
@@ -0,0 +1,69 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.codehaus.groovy.util;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * An iterator providing the columns of a long[][].
+ * In the case of an array with different size rows,
+ * the number of columns will be equal to the length of the smallest row.
+ *
+ * @since 5.0.0
+ */
+public class LongLongArrayColumnIterator implements Iterator<long[]> {
+    private final long[][] array;
+    private int columnIndex = 0;
+    private int numColumns;
+
+    public LongLongArrayColumnIterator(final long[][] array) {
+        Objects.requireNonNull(array);
+        this.array = array;
+        numColumns = Integer.MAX_VALUE;
+        for (long[] row: array) {
+            if (row.length < numColumns) numColumns = row.length;
+        }
+        if (numColumns == Integer.MAX_VALUE) numColumns = 0;
+    }
+
+    @Override
+    public boolean hasNext() {
+        return columnIndex < numColumns;
+    }
+
+    @Override
+    public long[] next() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        long[] col = new long[array.length];
+        for (int r = 0; r < array.length; r++) {
+            col[r] = array[r][columnIndex];
+        }
+        columnIndex++;
+        return col;
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException("Remove not supported for 
arrays");
+    }
+}

Reply via email to