Skip to content

Commit de07d86

Browse files
committed
Добавлена функция functional::stream
1 parent 4e5fc7b commit de07d86

File tree

4 files changed

+154
-7
lines changed

4 files changed

+154
-7
lines changed

src/main/java/com/annimon/ownlang/lib/MapValue.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public static MapValue merge(MapValue map1, MapValue map2) {
2020
result.map.putAll(map2.map);
2121
return result;
2222
}
23-
23+
2424
private final Map<Value, Value> map;
2525

2626
public MapValue(int size) {
@@ -30,6 +30,18 @@ public MapValue(int size) {
3030
public MapValue(Map<Value, Value> map) {
3131
this.map = map;
3232
}
33+
34+
public ArrayValue toPairs() {
35+
final int size = map.size();
36+
final ArrayValue result = new ArrayValue(size);
37+
int index = 0;
38+
for (Map.Entry<Value, Value> entry : map.entrySet()) {
39+
result.set(index++, new ArrayValue(new Value[] {
40+
entry.getKey(), entry.getValue()
41+
}));
42+
}
43+
return result;
44+
}
3345

3446
@Override
3547
public int type() {

src/main/java/com/annimon/ownlang/lib/modules/functional.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public void init() {
2828
Functions.set("dropwhile", new functional_dropwhile());
2929

3030
Functions.set("chain", new functional_chain());
31+
Functions.set("stream", new functional_stream());
3132
Functions.set("combine", new functional_combine());
3233
}
3334
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.annimon.ownlang.lib.modules.functions;
2+
3+
import com.annimon.ownlang.exceptions.TypeException;
4+
import com.annimon.ownlang.lib.*;
5+
6+
public final class functional_stream implements Function {
7+
8+
@Override
9+
public Value execute(Value... args) {
10+
Arguments.checkAtLeast(1, args.length);
11+
12+
if (args.length > 1) {
13+
return new StreamValue(new ArrayValue(args));
14+
}
15+
16+
final Value value = args[0];
17+
switch (value.type()) {
18+
case Types.MAP:
19+
return new StreamValue(((MapValue) value).toPairs());
20+
case Types.ARRAY:
21+
return new StreamValue((ArrayValue) value);
22+
default:
23+
throw new TypeException("Invalid argument. Array or map expected");
24+
}
25+
}
26+
27+
private static class StreamValue extends MapValue {
28+
29+
private final ArrayValue container;
30+
31+
public StreamValue(ArrayValue container) {
32+
super(12);
33+
this.container = container;
34+
init();
35+
}
36+
37+
private void init() {
38+
set("filter", wrapIntermediate(new functional_filter(false)));
39+
set("map", wrapIntermediate(new functional_map()));
40+
set("flatMap", wrapIntermediate(new functional_flatmap()));
41+
set("sortBy", wrapIntermediate(new functional_sortby()));
42+
set("takeWhile", wrapIntermediate(new functional_filter(true)));
43+
set("dropWhile", wrapIntermediate(new functional_dropwhile()));
44+
set("skip", this::skip);
45+
set("limit", this::limit);
46+
47+
set("reduce", wrapTerminal(new functional_reduce()));
48+
set("forEach", wrapTerminal(new functional_foreach()));
49+
set("toArray", args -> container);
50+
set("count", args -> NumberValue.of(container.size()));
51+
}
52+
53+
private Value skip(Value... args) {
54+
Arguments.check(1, args.length);
55+
56+
final int skipCount = args[0].asInt();
57+
final int size = container.size();
58+
59+
if (skipCount <= 0) return this;
60+
if (skipCount >= size) {
61+
return new StreamValue(new ArrayValue(0));
62+
}
63+
64+
final Value[] result = new Value[size - skipCount];
65+
System.arraycopy(container.getCopyElements(), skipCount, result, 0, result.length);
66+
return new StreamValue(new ArrayValue(result));
67+
}
68+
69+
private Value limit(Value... args) {
70+
Arguments.check(1, args.length);
71+
72+
final int limitCount = args[0].asInt();
73+
final int size = container.size();
74+
75+
if (limitCount >= size) return this;
76+
if (limitCount <= 0) {
77+
return new StreamValue(new ArrayValue(0));
78+
}
79+
80+
final Value[] result = new Value[limitCount];
81+
System.arraycopy(container.getCopyElements(), 0, result, 0, limitCount);
82+
return new StreamValue(new ArrayValue(result));
83+
}
84+
85+
private FunctionValue wrapIntermediate(Function f) {
86+
return wrap(f, true);
87+
}
88+
89+
private FunctionValue wrapTerminal(Function f) {
90+
return wrap(f, false);
91+
}
92+
93+
private FunctionValue wrap(Function f, boolean intermediate) {
94+
return new FunctionValue(args -> {
95+
final Value[] newArgs = new Value[args.length + 1];
96+
System.arraycopy(args, 0, newArgs, 1, args.length);
97+
newArgs[0] = container;
98+
final Value result = f.execute(newArgs);
99+
if (intermediate && result.type() == Types.ARRAY) {
100+
return new StreamValue((ArrayValue) result);
101+
}
102+
return result;
103+
});
104+
}
105+
}
106+
}
Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,39 @@
11
use "functional"
22

3-
def testFunctionalChain() {
3+
def testStream() {
44
data = [1,2,3,4,5,6,7]
5-
result = chain(data,
6-
::filter, def(x) = x <= 4,
7-
::sortby, def(x) = -x,
8-
::map, def(x) = x * 2,
9-
)
5+
result = stream(data)
6+
.filter(def(x) = x <= 4)
7+
.sortBy(def(x) = -x)
8+
.map(def(x) = x * 2)
9+
.toArray()
1010
assertEquals([8,6,4,2], result)
1111
}
12+
13+
def testSkip() {
14+
data = [1,2,3,4,5,6,7]
15+
assertEquals(7, stream(data).skip(0).count())
16+
assertEquals(5, stream(data).skip(2).count())
17+
assertEquals(0, stream(data).skip(7).count())
18+
assertEquals(0, stream(data).skip(20).count())
19+
}
20+
21+
def testLimit() {
22+
data = [1,2,3,4,5,6,7]
23+
assertEquals(0, stream(data).limit(0).count())
24+
assertEquals(2, stream(data).limit(2).count())
25+
assertEquals(7, stream(data).limit(7).count())
26+
assertEquals(7, stream(data).limit(20).count())
27+
}
28+
29+
def testTakeWhile() {
30+
data = [2,4,6,5,6,7,8]
31+
assertEquals([2, 4, 6], stream(data).takeWhile(def(x) = x % 2 == 0).toArray())
32+
assertEquals(0, stream(data).takeWhile(def(x) = x % 2 != 0).count())
33+
}
34+
35+
def testDropWhile() {
36+
data = [2,4,6,5,6,7,8]
37+
assertEquals([5, 6, 7, 8], stream(data).dropWhile(def(x) = x % 2 == 0).toArray())
38+
assertEquals(data, stream(data).dropWhile(def(x) = x % 2 != 0).toArray())
39+
}

0 commit comments

Comments
 (0)