[functional] Move indexed variant of Stream.forEach to Stream,forEachIndexed

This commit is contained in:
aNNiMON 2023-10-05 18:23:20 +03:00 committed by Victor Melnik
parent d643f596a8
commit 2bb5e45517
5 changed files with 62 additions and 24 deletions

View File

@ -30,6 +30,7 @@ class StreamValue extends MapValue {
set("reduce", wrapTerminal(new functional_reduce())); set("reduce", wrapTerminal(new functional_reduce()));
set("forEach", wrapTerminal(new functional_forEach())); set("forEach", wrapTerminal(new functional_forEach()));
set("forEachIndexed", wrapTerminal(new functional_forEachIndexed()));
set("toArray", args -> container); set("toArray", args -> container);
set("joining", container::joinToString); set("joining", container::joinToString);
set("count", args -> NumberValue.of(container.size())); set("count", args -> NumberValue.of(container.size()));

View File

@ -15,17 +15,16 @@ public final class functional_forEach implements Function {
} }
static Value forEach(Value container, Function consumer) { static Value forEach(Value container, Function consumer) {
final int argsCount = consumer.getArgsCount();
return switch (container.type()) { return switch (container.type()) {
case Types.STRING -> forEachString((StringValue) container, argsCount, consumer); case Types.STRING -> forEachString((StringValue) container, consumer);
case Types.ARRAY -> forEachArray((ArrayValue) container, argsCount, consumer); case Types.ARRAY -> forEachArray((ArrayValue) container, consumer);
case Types.MAP -> forEachMap((MapValue) container, consumer); case Types.MAP -> forEachMap((MapValue) container, consumer);
default -> throw new TypeException("Cannot iterate " + Types.typeToString(container.type())); default -> throw new TypeException("Cannot iterate " + Types.typeToString(container.type()));
}; };
} }
static StringValue forEachString(StringValue string, int argsCount, Function consumer) { static StringValue forEachString(StringValue string, Function consumer) {
if (argsCount == 2) { if (consumer.getArgsCount() == 2) {
for (char ch : string.asString().toCharArray()) { for (char ch : string.asString().toCharArray()) {
consumer.execute(new StringValue(String.valueOf(ch)), NumberValue.of(ch)); consumer.execute(new StringValue(String.valueOf(ch)), NumberValue.of(ch));
} }
@ -37,17 +36,10 @@ public final class functional_forEach implements Function {
return string; return string;
} }
static ArrayValue forEachArray(ArrayValue array, int argsCount, Function consumer) { static ArrayValue forEachArray(ArrayValue array, Function consumer) {
if (argsCount == 2) {
int index = 0;
for (Value element : array) {
consumer.execute(element, NumberValue.of(index++));
}
} else {
for (Value element : array) { for (Value element : array) {
consumer.execute(element); consumer.execute(element);
} }
}
return array; return array;
} }

View File

@ -0,0 +1,31 @@
package com.annimon.ownlang.modules.functional;
import com.annimon.ownlang.exceptions.TypeException;
import com.annimon.ownlang.lib.*;
public final class functional_forEachIndexed implements Function {
@Override
public Value execute(Value[] args) {
Arguments.check(2, args.length);
final Value container = args[0];
final Function consumer = ValueUtils.consumeFunction(args[1], 1);
return forEachIndexed(container, consumer);
}
static Value forEachIndexed(Value container, Function consumer) {
if (container.type() == Types.ARRAY) {
return forEachIndexedArray((ArrayValue) container, consumer);
}
// Only used in Streams -> no Map implementation
throw new TypeException("Cannot iterate " + Types.typeToString(container.type()));
}
static ArrayValue forEachIndexedArray(ArrayValue array, Function consumer) {
int index = 0;
for (Value element : array) {
consumer.execute(element, NumberValue.of(index++));
}
return array;
}
}

View File

@ -1,6 +1,6 @@
use std, functional use std, functional
def testArrayForeach1Arg() { def testArrayForeachArg() {
sum = 0 sum = 0
foreach([1, 2, 3], def(v) { foreach([1, 2, 3], def(v) {
sum += v sum += v
@ -8,14 +8,6 @@ def testArrayForeach1Arg() {
assertEquals(6, sum) assertEquals(6, sum)
} }
def testArrayForeach2Args() {
sum = 0
foreach([1, 2, 3], def(v, index) {
sum += v * index
})
assertEquals(1 * 0 + 2 * 1 + 3 * 2, sum)
}
def testStringForeach1Arg() { def testStringForeach1Arg() {
sum = 0 sum = 0
foreach("abcd", def(s) { foreach("abcd", def(s) {

View File

@ -79,6 +79,28 @@ def testSorted() {
assertEquals([-2,3,4,-5,6,6,-8], stream(data).sorted(def(a,b) = abs(a) - abs(b)).toArray()) assertEquals([-2,3,4,-5,6,6,-8], stream(data).sorted(def(a,b) = abs(a) - abs(b)).toArray())
} }
def testForEachArrayIndexed() {
data = [1, 2, 3]
sum = 0
stream(data)
.forEachIndexed(def(v, index) {
sum += (v * index)
})
assertEquals(1 * 0 + 2 * 1 + 3 * 2, sum)
}
def testForEachMapIndexed() {
data = {"a": "1", "b": 2}
result = ""
stream(data)
.sorted()
.forEachIndexed(def(entry, index) {
extract(key, value) = entry
result += "" + key + value + index
})
assertEquals("a10b21", result)
}
def reverse(container) { def reverse(container) {
size = length(container) size = length(container)
result = newarray(size) result = newarray(size)