用Java实现的不可变列表

概述


  • 函数式编程思想的不可变列表,所有成员都是一经创建不可变的。灵感来自于 Scala List
  • 用递归算法实现的数据结构,同时也是用来实现递归算法的数据结构,FList具备部分与整体一致的结构设计,同时尾部都有一个nil作为递归跳出点。
  • “左折叠”和“右折叠”是非常强大的操作:
    • foldLeft :   op(a,b,c) = op(op(op(a),b),c)
    • foldRight : op(a,b,c) = op(a,op(b,op(c)))
  • 大多数列表操作都可以通过折叠操作实现,不可变列表自身的很多方法也是通过折叠操作实现的,如反向、合并、筛选、排序等。
  • FList 的很多方法都是接受函数作为参数的 “高阶方法”,比如:
    • generate:不可变列表生成器,
      • 第一个参数是作为种子的初始列表,
      • 第二个是由当前列表推出下一个元素的函数,例如:x -> x.head + 1
      • 第三个是新生成元素的个数。
    • filter : 过滤,留下符合条件的
    • remove:反向过滤,删除符合条件的
    • map :列表元素类型转变
    • reduce :聚合
    • exist:是否存在一个判断
    • forall :是否全部符合的判断
    • count:按过滤条件计数
    • foreach :对列表元素依次执行操作
    • isort:插入排序,需传入比较函数
    • msort:归并排序,需传入比较函数

源码


这是一个无外部依赖可直接运行的代码

package demo;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.StringJoiner;
import java.util.function.*;
import java.util.stream.Stream;

public class Demo {

    public static void main(String[] args) {
        ArrayList<Integer> list = FList
                .generate(FList.of(0), x -> x.head + 1, 10)
                .map(x -> x * x)
                .filter(x -> x % 2 == 0)
                .foldRight(new ArrayList<>(), (x, y) -> {
                    x.add(y);
                    return x;
                });
        System.out.println(list.parallelStream().reduce(0, (x, y) -> x + y));
        
        
        list = Stream.iterate(0, x -> x + 1).limit(9)
                .map(x -> x * x)
                .filter(x -> x % 2 == 0)
                .collect(ArrayList::new,
                        (x, y) -> x.add(y),
                        ArrayList::addAll);
        System.out.println(list.parallelStream().reduce(0, (x, y) -> x + y));
    }
}

final class FList<T> {

    public final T head;
    public final FList<T> tail;
    public final int length;
    public final boolean isEmpty;

    private FList() {
        head = null;
        tail = null;
        isEmpty = true;
        length = 0;
    }

    private FList(T i, FList<T> n) {
        head = i;
        tail = n;
        isEmpty = false;
        length = n.length + 1;
    }

    public FList<T> add(T item) {
        return new FList<>(item, this);
    }

    public FList<T> reverse() {
        return foldLeft(nil, (x, y) -> x.add(y));
    }

    public <U> U foldLeft(U i, BiFunction<U, T, U> f) {
        return isEmpty ? i : tail.foldLeft(f.apply(i, head), f);
    }

    public <U> U foldRight(U i, BiFunction<U, T, U> f) {
        return isEmpty ? i : f.apply(tail.foldRight(i, f), head);
    }

    public FList<T> filter(Predicate<T> p) {
        return foldRight(nil, (x, y) -> p.test(y) ? x.add(y) : x);
    }

    public FList<T> remove(Predicate<T> p) {
        return filter(p.negate());
    }

    public boolean exist(Predicate<T> p) {
        return !isEmpty && (p.test(head) || tail.exist(p));
    }

    public boolean forAll(Predicate<T> p) {
        return !exist(p.negate());
    }

    public int count(Predicate<T> p) {
        return foldLeft(0, (x, y) -> p.test(y) ? x + 1 : x);
    }

    public FList<T> merge(FList<T> other) {
        return other == null || other.isEmpty ? this : other.foldRight(this, (x, y) -> x.add(y));
    }

    @Override
    public String toString() {
        return foldRight(new StringJoiner(",", "[", "]"), (x, y) -> x.add(y.toString())).toString();
    }

    public FList<T> sort(Comparator<T> c) {
        return isEmpty ? nil : ins(c, head, tail.sort(c));
    }

    public FList<T> drop(int n) {
        return n <= 0 || isEmpty ? this : tail.drop(n - 1);
    }

    public void foreach(Consumer<T> a) {
        if (!isEmpty) {
            a.accept(head);
            tail.foreach(a);
        }
    }

    public <R> FList<R> map(Function<T, R> map) {
        return foldRight(nil, (x, y) -> x.add(map.apply(y)));
    }

    public T reduce(T i, BinaryOperator<T> f) {
        return isEmpty ? i : tail.reduce(f.apply(i, head), f);
    }

    public static final FList nil = new FList<>();

    public static <T> FList<T> of(T... args) {
        return a2f(args, args.length - 1);
    }

    private static <T> FList<T> a2f(T[] a, int i) {
        return i < 0 ? nil : new FList<>(a[i], a2f(a, i - 1));
    }

    private static <T> FList<T> ins(Comparator<T> c, T h, FList<T> t) {
        return t.isEmpty || c.compare(h, t.head) > -1 ? t.add(h) : ins(c, h, t.tail).add(t.head);
    }

    public static <T> FList<T> generate(FList<T> r, Function<FList<T>, T> f, int m) {
        return m == 1 ? r : generate(new FList<>(f.apply(r), r), f, m - 1);
    }
}

用数学归纳法生成数组


  1. 给出一个递归结束的值. 例如: f(1) =1
  2. 指定 f =  f(n-1). 
  3. 用 f 定义 f(n) . 例如:f(n) = f(n-1) + 1
//奇数数组 ,odd(5) = [1,3,5,7,9]
    private static FList<Integer> odd(int n) {
        //定义f(1)的值
        if (n == 1)
            return FList.of(1);
        //指定 f(n-1)的函数
        FList<Integer> f = odd(n - 1);
        //根据f(n-1)的函数推断f(n)的值
        return f.add(f.head + 2);
    }
    //单行代码:FList.generate(FList.of(1), x -> x.head + 2, 5)
    //阶乘数组 fact(10) = [1,2,6,24,120,720,5040,40320,362880,3628800]
    private static FList<Integer> fact(int n) {
        if (n <= 1)
            return FList.of(1);
        FList<Integer> f = fact(n - 1);
        return f.add(f.head * (f.length + 1));
    }
    //单行代码:FList.generate(FList.of(1), x -> x.head * (x.length + 1), 10)
    //菲波拉契亚数组 fib(10) = [1,1,2,3,5,8,13,21,34,55]
    private static FList<Integer> fib(int n) {
        if (n <= 2)
            return FList.of(1, 1);
        FList<Integer> f = fib(n - 1);
        return f.add(f.head + f.tail.head);
    }
    //单行代码:FList.generate(FList.of(1, 1), x -> x.head + x.tail.head, 9)
/* 
π = 2 + 2/3 + 2/3*2/5 + 2/3*2/5*3/7  + ... + f(n-1) * n/(2*n+1)
数学归纳法生成数列的应用:计算圆周率的近似值 
*/
import j.i.FList;
public class Main {
    public static void main(String[] args) {
        System.out.println(pi(50).reduce(0d, (x, y) -> x + y));
        //=> 3.141592653589793
    }
    private static FList<Double> pi(int n) {
        if (n == 0)
            return FList.of(2d);
        FList<Double> f = pi(n - 1);
        return f.add(f.head * n / (2 * n + 1));
    }
}
//单行代码
FList.generate(FList.of(2d), x -> x.head * x.length / (x.length * 2 + 1), 51).reduce(0d, (x, y) -> x + y);
//=> 3.141592653589793

猜你喜欢

转载自www.cnblogs.com/scala/p/9151658.html