1. 程式人生 > >用go語言實現類似java8的Stream

用go語言實現類似java8的Stream

4.4 代碼 歸納 Go語言 浮點 print jdk 是我 遞歸

JDK8 Stream 是一個支持泛型和函數式數據流,使用起來非常強大方便。最近在學習 go 語言我就用 go 模仿了一下類似的功能,
由於 go 對泛型、函數式的支持比較有限,感覺泛型和函數式這一塊實現起來有些別扭,可能是我不會用,不當之處請高手指點。

Stream 具備部分與整體一致的結構設計,可很方便用來實現各種遞歸算法,尾部有一個Nil作為遞歸跳出點。
“左折疊”和“右折疊” 是非常強大的操作,大多數其它操作都可以通過折疊實現的,
Stream 自身的很多方法也是通過折疊操作實現的,如反向、合並、篩選、排序等。
Stream 的參數類型為空接口,支持泛型類型。

Stream 提供的很多方法都是接受函數作為參數的 “高階方法”,比如:filter ,map ,reduce

Stream 支持用數學歸納法生成各種數列,步驟非常簡單:
1、給出一個遞歸結束的值. 例如: f(1) =1
2、指定 f(n-1).
3、用f(n-1)定義f(n). 例如:f(n)= f(n-1) + 1

goStream 的源代碼如下


package stream
 
import (
    "fmt"
    "strings"
)
 
//泛型類型定義
type T interface{}
type U interface{}
 
//流計算數據結構定義
type Stream struct {
    Head     T
    Tail     *Stream
    Length   int
    NotEmpty bool
}
 
var Nil = Stream{}
 
func Generate(r Stream, f func(Stream) T, m int) Stream {
 
    if m == 1 {
        return r
    } else {
        return Generate(New(f(r), &r), f, m-1)
    }
}
 
func New(head T, tail *Stream) Stream {
    return Stream{head, tail, tail.Length + 1, true}
}
 
func (s Stream) Add(i T) Stream {
    return New(i, &s)
}
 
func (s Stream) Addall(i ...T) Stream {
    for _, v := range i {
        s = s.Add(v)
    }
    return s
}
 
//左折疊 用於實現 reduce 的功能
func (s Stream) FoldLeft(i U, f func(U, T) U) U {
    if s.NotEmpty {
        return s.Tail.FoldLeft(f(i, s.Head), f)
    } else {
        return i
    }
}
 
//右折疊
func (s Stream) FoldRight(i U, f func(U, T) U) U {
    if s.NotEmpty {
        return f(s.Tail.FoldRight(i, f), s.Head)
    } else {
        return i
    }
}
 
//合並兩個 Stream
func (s Stream) Merge(t Stream) Stream {
    if t.NotEmpty {
        return t.FoldRight(s, func(u U, t T) U {
            return u.(Stream).Add(t)
        }).(Stream)
 
    } else {
        return s
    }
}
 
//倒序
func (s Stream) Reverse() Stream {
    return s.FoldLeft(Nil, func(u U, t T) U {
        return u.(Stream).Add(t)
    }).(Stream)
}
 
//Map
func (s Stream) Map(f func(T) U) Stream {
    return s.FoldRight(Nil, func(u U, t T) U {
        return u.(Stream).Add(f(t))
    }).(Stream)
}
 
//Reduce
func (s Stream) Reduce(i T, f func(T, T) T) T {
    if s.NotEmpty {
        return s.Tail.Reduce(f(i, s.Head), f)
    } else {
        return i
    }
}
 
//過濾
func (s Stream) Filter(f func(T) bool) Stream {
    return s.FoldRight(Nil, func(u U, t T) U {
        if f(t) {
            return u.(Stream).Add(t)
        } else {
            return u
        }
    }).(Stream)
}
 
//歸並排序
func (s Stream) Sort(c func(T,T) bool) Stream {

	n := s.Length / 2

	if n == 0 {
		return s
	}else{
		x,y := split(s, Nil, n)
		return merge(x.Sort(c),y.Sort(c),c)
	}
}


func split(x,y Stream , n int) (Stream,Stream) {

	if (n == 0 || !x.NotEmpty) {
		return x,y
	}
	return split(*x.Tail, y.Add(x.Head), n - 1);
}

 
func merge(x,y Stream , c func(T,T) bool) Stream {

	if (!x.NotEmpty){
        return y;
	}
	if (!y.NotEmpty){
		return x;
	}
	if c(x.Head,y.Head) {
		return merge(*x.Tail, y, c).Add(x.Head)
	}else{
		return merge(x, *y.Tail, c).Add(y.Head);
	}
}

//格式化顯示 Stream 的所有項
func (s Stream) ToString() string {
    return "{" + strings.Join(s.FoldRight([]string{}, func(u U, t T) U {
        return append(u.([]string), fmt.Sprintf("%v", t))
    }).([]string), ",") + "}"
}

使用的樣例


package main
 
import (
    "fmt"
	. "./stream"
	"strings"
)
 
func main() {

	x := Generate(Nil.Add(1),func(s Stream) T {return s.Head.(int)+1},50) // {1,2,3,...,48,49,50}
	x = x.Map(func(t T) U {
        p := t.(int) //平方映射
        return p * p
    }).Filter(func(t T) bool {
        return t.(int) % 2 == 0 //偶數過濾
    })

	//計算所有項的和
	fmt.Printf("sum %s = %d\n",x.ToString(),x.FoldLeft(0,func(u U, t T) U {
		return u.(int) + t.(int)
	})) //22100


	//浮點數列表求和
	y := Nil.Addall(3.5, 4.3, 2.6, 1.1, 7.83, 4.42)
    fmt.Printf("%.2f\n", y.Reduce(0.0, func(t T, t2 T) T {
        return t.(float64) + t2.(float64)
    }))

	
	//排序
	z := Nil.Addall(4,3,7,6,2,1,9,5,8,0).Sort(func(x,y T) bool {
		return x.(int) > y.(int)
	})
	fmt.Println(z.ToString()) //{0,1,2,3,4,5,6,7,8,9}


	//列出包含a字符的字符串
    g := Nil.Addall("aaa", "bbb", "aba", "ccc", "cbb", "cba")
    fmt.Println(g.Filter(func(t T) bool {
        return strings.Contains(t.(string), "a")
    }).ToString())
 
    //生成斐波拉契亞數列 的前 20 項
    fmt.Println(Generate(Nil.Addall(1, 1), func(s Stream) T {
        return s.Head.(int) + s.Tail.Head.(int)
    }, 19).ToString())
 
 
    //通過數列 π = 2 + 2/3 + 2/3*2/5 + 2/3*2/5*3/7  + ... + f(n-1) * n/(2*n+1) 計算圓周率的值
    fmt.Println(Generate(Nil.Add(2.0), func(s Stream) T {
        n := s.Length
        return s.Head.(float64) * float64(n) / (float64(n)*2 + 1)
    }, 51).Reduce(0.0, func(t T, t2 T) T {
        return t.(float64) + t2.(float64)
    }))
}

用go語言實現類似java8的Stream