mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
[functional] Add groupby and Stream.groupBy
This commit is contained in:
parent
7a64d7f99d
commit
c3a893ea25
@ -31,6 +31,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("forEachIndexed", wrapTerminal(new functional_forEachIndexed()));
|
||||||
|
set("groupBy", wrapTerminal(new functional_groupBy()));
|
||||||
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()));
|
||||||
|
@ -27,6 +27,7 @@ public final class functional implements Module {
|
|||||||
result.put("sortby", new functional_sortBy());
|
result.put("sortby", new functional_sortBy());
|
||||||
result.put("takewhile", new functional_takeWhile());
|
result.put("takewhile", new functional_takeWhile());
|
||||||
result.put("dropwhile", new functional_dropWhile());
|
result.put("dropwhile", new functional_dropWhile());
|
||||||
|
result.put("groupby", new functional_groupBy());
|
||||||
|
|
||||||
result.put("chain", new functional_chain());
|
result.put("chain", new functional_chain());
|
||||||
result.put("stream", new functional_stream());
|
result.put("stream", new functional_stream());
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.annimon.ownlang.modules.functional;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.exceptions.TypeException;
|
||||||
|
import com.annimon.ownlang.lib.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public final class functional_groupBy implements Function {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value execute(Value[] args) {
|
||||||
|
Arguments.check(2, args.length);
|
||||||
|
|
||||||
|
final Value container = args[0];
|
||||||
|
final Function classifier = ValueUtils.consumeFunction(args[1], 1);
|
||||||
|
return groupBy(container, classifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value groupBy(Value container, Function classifier) {
|
||||||
|
if (container.type() == Types.ARRAY) {
|
||||||
|
return groupByArray((ArrayValue) container, classifier);
|
||||||
|
}
|
||||||
|
if (container.type() == Types.MAP) {
|
||||||
|
return groupByMap((MapValue) container, classifier);
|
||||||
|
}
|
||||||
|
throw new TypeException("Invalid first argument. Array or map expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("Java8MapApi")
|
||||||
|
static Value groupByArray(ArrayValue array, Function classifier) {
|
||||||
|
final var result = new LinkedHashMap<Value, List<Value>>();
|
||||||
|
for (Value element : array) {
|
||||||
|
final var key = classifier.execute(element);
|
||||||
|
var container = result.get(key);
|
||||||
|
if (container == null) {
|
||||||
|
container = new ArrayList<>();
|
||||||
|
result.put(key, container);
|
||||||
|
}
|
||||||
|
container.add(element);
|
||||||
|
}
|
||||||
|
return fromMapOfArrays(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Value groupByMap(MapValue map, Function classifier) {
|
||||||
|
final var result = new LinkedHashMap<Value, Value>();
|
||||||
|
for (Map.Entry<Value, Value> element : map) {
|
||||||
|
final var k = element.getKey();
|
||||||
|
final var v = element.getValue();
|
||||||
|
final var key = classifier.execute(k, v);
|
||||||
|
var container = (MapValue) result.get(key);
|
||||||
|
if (container == null) {
|
||||||
|
container = new MapValue(10);
|
||||||
|
result.put(key, container);
|
||||||
|
}
|
||||||
|
container.set(k, v);
|
||||||
|
}
|
||||||
|
return new MapValue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MapValue fromMapOfArrays(Map<Value, List<Value>> map) {
|
||||||
|
final var result = new LinkedHashMap<Value, Value>();
|
||||||
|
map.forEach((key, value) -> result.put(key, new ArrayValue(value)));
|
||||||
|
return new MapValue(result);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
use std, functional
|
||||||
|
|
||||||
|
def testArraysGroupBy() {
|
||||||
|
arr = [1, 2, 3, 4, 1, 2, 3, 1, 2, 3]
|
||||||
|
result = groupby(arr, def(v) = v % 2 == 0)
|
||||||
|
assertEquals([2, 4, 2, 2], result[true])
|
||||||
|
assertEquals([1, 3, 1, 3, 1, 3], result[false])
|
||||||
|
}
|
||||||
|
|
||||||
|
def testMapsGroupBy() {
|
||||||
|
map = {"abc": 123, "test1": 234, "test2": 345, "test3": 456, "def": 567}
|
||||||
|
result = groupby(map, def(k, v) = k.startsWith("test"))
|
||||||
|
assertEquals({"test1": 234, "test2": 345, "test3": 456}, result[true])
|
||||||
|
assertEquals({"abc": 123, "def": 567}, result[false])
|
||||||
|
}
|
@ -53,6 +53,15 @@ def testCustom() {
|
|||||||
assertEquals([5,6,4,2], stream(data).custom(::reverse).toArray())
|
assertEquals([5,6,4,2], stream(data).custom(::reverse).toArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def reverse(container) {
|
||||||
|
size = length(container)
|
||||||
|
result = newarray(size)
|
||||||
|
for i : range(size) {
|
||||||
|
result[size - i - 1] = container[i]
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
def testJoining() {
|
def testJoining() {
|
||||||
data = [1,2,3,4]
|
data = [1,2,3,4]
|
||||||
assertEquals("1234", stream(data).joining())
|
assertEquals("1234", stream(data).joining())
|
||||||
@ -101,11 +110,18 @@ def testForEachMapIndexed() {
|
|||||||
assertEquals("a10b21", result)
|
assertEquals("a10b21", result)
|
||||||
}
|
}
|
||||||
|
|
||||||
def reverse(container) {
|
def testArraysGroupBy() {
|
||||||
size = length(container)
|
data = [1, 2, 3, 4, 1, 2, 3, 1, 2, 3]
|
||||||
result = newarray(size)
|
result = stream(data)
|
||||||
for i : range(size) {
|
.groupBy(def(v) = v % 2 == 0)
|
||||||
result[size - i - 1] = container[i]
|
assertEquals([2, 4, 2, 2], result[true])
|
||||||
}
|
assertEquals([1, 3, 1, 3, 1, 3], result[false])
|
||||||
return result
|
}
|
||||||
|
|
||||||
|
def testMapsGroupBy() {
|
||||||
|
data = {"abc": 123, "test1": 234, "test2": 345, "test3": 456, "def": 567}
|
||||||
|
result = stream(data)
|
||||||
|
.groupBy(def(entry) = entry[0].startsWith("test"))
|
||||||
|
assertEquals([["test1", 234], ["test2", 345], ["test3", 456]], sort(result[true]))
|
||||||
|
assertEquals([["abc", 123], ["def", 567]], sort(result[false]))
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user