feat(Go-Tool):
2020/12/16: 添加YAML和结构体转换工具
This commit is contained in:
@@ -3,19 +3,11 @@ module Go-Tool
|
|||||||
go 1.13
|
go 1.13
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75 // indirect
|
github.com/ahmetb/go-linq v3.0.0+incompatible
|
||||||
github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible // indirect
|
|
||||||
github.com/ahmetb/go-linq v2.0.0-rc0+incompatible
|
|
||||||
github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 // indirect
|
|
||||||
github.com/go-ini/ini v1.57.0
|
github.com/go-ini/ini v1.57.0
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
|
||||||
github.com/json-iterator/go v1.1.10
|
github.com/json-iterator/go v1.1.10
|
||||||
github.com/kardianos/govendor v1.0.9 // indirect
|
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
|
||||||
github.com/stretchr/testify v1.5.1 // indirect
|
github.com/stretchr/testify v1.5.1 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200428200454-593003d681fa // indirect
|
|
||||||
golang.org/x/tools v0.0.0-20200429213335-127c98bd7927 // indirect
|
|
||||||
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
|
|
||||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.2.8 // indirect
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,65 +1,45 @@
|
|||||||
github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75 h1:xGHheKK44eC6K0u5X+DZW/fRaR1LnDdqPHMZMWx5fv8=
|
github.com/ahmetb/go-linq v3.0.0+incompatible h1:qQkjjOXKrKOTy83X8OpRmnKflXKQIL/mC/gMVVDMhOA=
|
||||||
github.com/Bowery/prompt v0.0.0-20190916142128-fa8279994f75/go.mod h1:4/6eNcqZ09BZ9wLK3tZOjBA1nDj+B0728nlX5YRlSmQ=
|
github.com/ahmetb/go-linq v3.0.0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY=
|
||||||
github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible h1:8q+6K5jJ2RCTD7v7VxMfuUdHyU22GZi+qMY0hpLTnVc=
|
|
||||||
github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible/go.mod h1:IBvGwXyZVvXuN8KIbGCK53k+fzCKOmAdYhobMdJXOck=
|
|
||||||
github.com/ahmetb/go-linq v2.0.0-rc0+incompatible h1:H8yA1M8T+1/pyPRUwSOyc30MFrtiP9vgJ2s+lgdaQlM=
|
|
||||||
github.com/ahmetb/go-linq v2.0.0-rc0+incompatible/go.mod h1:PFffvbdbtw+QTB0WKRP0cNht7vnCfnGlEpak/DVg5cY=
|
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185 h1:3T8ZyTDp5QxTx3NU48JVb2u+75xc040fofcBaN+6jPA=
|
|
||||||
github.com/dchest/safefile v0.0.0-20151022103144-855e8d98f185/go.mod h1:cFRxtTwTOJkz2x3rQUNCYKWC93yP1VKjR8NUhqFxZNU=
|
|
||||||
github.com/go-ini/ini v1.57.0 h1:Qwzj3wZQW+Plax5Ntj+GYe07DfGj1OH+aL1nMTMaNow=
|
github.com/go-ini/ini v1.57.0 h1:Qwzj3wZQW+Plax5Ntj+GYe07DfGj1OH+aL1nMTMaNow=
|
||||||
github.com/go-ini/ini v1.57.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.57.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/kardianos/govendor v1.0.9 h1:WOH3FcVI9eOgnIZYg96iwUwrL4eOVx+aQ66oyX2R8Yc=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/kardianos/govendor v1.0.9/go.mod h1:yvmR6q9ZZ7nSF5Wvh40v0wfP+3TwwL8zYQp+itoZSVM=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200428200454-593003d681fa h1:yMbJOvnfYkO1dSAviTu/ZguZWLBTXx4xE3LYrxUCCiA=
|
|
||||||
golang.org/x/sys v0.0.0-20200428200454-593003d681fa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20200429213335-127c98bd7927 h1:qunaQbmBN1l/xZt8mr6MLr8G/IOFiMbXvxYbGVqKlyw=
|
|
||||||
golang.org/x/tools v0.0.0-20200429213335-127c98bd7927/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
|
||||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
|
||||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
|||||||
@@ -70,6 +70,8 @@
|
|||||||
|
|
||||||
2020/12/15:添加前缀树工具,实现前缀搜索和字符串搜索功能
|
2020/12/15:添加前缀树工具,实现前缀搜索和字符串搜索功能
|
||||||
|
|
||||||
|
2020/12/16: 添加YAML和结构体转换工具
|
||||||
|
|
||||||
# mod vendor模式加载包
|
# mod vendor模式加载包
|
||||||
通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到
|
通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* @Author : huangzj
|
||||||
|
* @Time : 2020/12/16 11:56
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
"io/ioutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
//把文件中的yaml结构转换成结构体
|
||||||
|
func GetYamlToStructByFile(fileName string, object interface{}) error {
|
||||||
|
yamlFile, err := ioutil.ReadFile(fileName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = yaml.Unmarshal(yamlFile, object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过字符串的Yaml转换成结构体
|
||||||
|
func GetYamlToStructByString(content string, object interface{}) error {
|
||||||
|
err := yaml.Unmarshal([]byte(content), object)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//通过字符串的Yaml转换成map
|
||||||
|
func GetYamlToMap(content string) (error, map[interface{}]interface{}) {
|
||||||
|
m := make(map[interface{}]interface{}, 0)
|
||||||
|
err := yaml.Unmarshal([]byte(content), m)
|
||||||
|
if err != nil {
|
||||||
|
return err, m
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, m
|
||||||
|
}
|
||||||
|
|
||||||
|
//把结构体转换成yaml的字符串
|
||||||
|
func GetStructToYaml(object interface{}) (error, string) {
|
||||||
|
result, err := yaml.Marshal(object)
|
||||||
|
if err != nil {
|
||||||
|
return err, ""
|
||||||
|
}
|
||||||
|
return nil, string(result)
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* @Author : huangzj
|
||||||
|
* @Time : 2020/12/16 11:56
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MySQLConfig struct {
|
||||||
|
User string `yaml:"user"`
|
||||||
|
Password string `yaml:"password"`
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
DbName string `yaml:"dbname"`
|
||||||
|
}
|
||||||
|
type RedisConfig struct {
|
||||||
|
Host string `yaml:"host"`
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
Auth string `yaml:"-"` //标签表示不显示
|
||||||
|
}
|
||||||
|
type NginxProxyConfig struct {
|
||||||
|
Counter int `yaml:"counter"`
|
||||||
|
NginxList []string `yaml:"nginx_list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServiceYaml struct {
|
||||||
|
MySQL MySQLConfig `yaml:"mysql"`
|
||||||
|
Redis RedisConfig `yaml:"redis"`
|
||||||
|
NginxProxy NginxProxyConfig `yaml:"nginx_proxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestYamlToStructByFile(t *testing.T) {
|
||||||
|
config := new(ServiceYaml)
|
||||||
|
_ = GetYamlToStructByFile("config.yaml", &config)
|
||||||
|
|
||||||
|
fmt.Printf("MySQL host : %s, port : %d, user : %s, password : %s, db_name : %s \n",
|
||||||
|
config.MySQL.Host, config.MySQL.Port, config.MySQL.User, config.MySQL.Password, config.MySQL.DbName)
|
||||||
|
|
||||||
|
fmt.Printf("Redis host : %s, port %d, auth : %s\n",
|
||||||
|
config.Redis.Host, config.Redis.Port, config.Redis.Auth)
|
||||||
|
|
||||||
|
fmt.Printf("Vip Counter: %d, Vip List : %v\n", config.NginxProxy.Counter, config.NginxProxy.NginxList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestYamlToStructByString(t *testing.T) {
|
||||||
|
config := new(ServiceYaml)
|
||||||
|
fileByte, _ := ioutil.ReadFile("config.yaml")
|
||||||
|
_ = GetYamlToStructByString(string(fileByte), &config)
|
||||||
|
|
||||||
|
fmt.Printf("MySQL host : %s, port : %d, user : %s, password : %s, db_name : %s \n",
|
||||||
|
config.MySQL.Host, config.MySQL.Port, config.MySQL.User, config.MySQL.Password, config.MySQL.DbName)
|
||||||
|
|
||||||
|
fmt.Printf("Redis host : %s, port %d, auth : %s\n",
|
||||||
|
config.Redis.Host, config.Redis.Port, config.Redis.Auth)
|
||||||
|
|
||||||
|
fmt.Printf("Vip Counter: %d, Vip List : %v\n", config.NginxProxy.Counter, config.NginxProxy.NginxList)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestYamlToMap(t *testing.T) {
|
||||||
|
fileByte, _ := ioutil.ReadFile("config.yaml")
|
||||||
|
_, m := GetYamlToMap(string(fileByte))
|
||||||
|
for key, value := range m {
|
||||||
|
fmt.Println(fmt.Sprintf("key:%v ,value: %v", key, value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStructToYaml(t *testing.T) {
|
||||||
|
config := new(ServiceYaml)
|
||||||
|
fileByte, _ := ioutil.ReadFile("config.yaml")
|
||||||
|
_ = GetYamlToStructByString(string(fileByte), &config)
|
||||||
|
_, result := GetStructToYaml(config)
|
||||||
|
fmt.Println(result)
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
mysql:
|
||||||
|
user: root
|
||||||
|
password: 123456
|
||||||
|
host: 192.198.1.1
|
||||||
|
port: 3306
|
||||||
|
dbname: mdb
|
||||||
|
redis:
|
||||||
|
host: 192.168.1.1
|
||||||
|
port: 1234
|
||||||
|
auth: 123456
|
||||||
|
nginx_proxy:
|
||||||
|
counter: 3
|
||||||
|
nginx_list: [
|
||||||
|
192.168.1.1,
|
||||||
|
192.168.1.2,
|
||||||
|
192.168.1.3
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
获取包命令: https://gopkg.in/yaml.v2
|
||||||
|
|
||||||
|
文档地址: https://gopkg.in/yaml.v2
|
||||||
|
|
||||||
|
参考地址:http://www.topgoer.com/%E5%85%B6%E4%BB%96/Yaml%E7%BC%96%E7%A0%81%E5%92%8C%E8%A7%A3%E7%A0%81.html
|
||||||
-1
@@ -2,7 +2,6 @@ sudo: false
|
|||||||
|
|
||||||
language: go
|
language: go
|
||||||
go:
|
go:
|
||||||
- 1.5
|
|
||||||
- 1.7
|
- 1.7
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
|
|||||||
+188
-1
@@ -1,3 +1,191 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright 2016 Ahmet Alp Balkan
|
Copyright 2016 Ahmet Alp Balkan
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -11,4 +199,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
|
|
||||||
|
|||||||
+91
-10
@@ -1,16 +1,21 @@
|
|||||||
# go-linq [](https://godoc.org/github.com/ahmetalpbalkan/go-linq) [](https://travis-ci.org/ahmetalpbalkan/go-linq) [](https://coveralls.io/github/ahmetalpbalkan/go-linq?branch=master) [](https://goreportcard.com/report/github.com/ahmetalpbalkan/go-linq)
|
# go-linq [](https://godoc.org/github.com/ahmetalpbalkan/go-linq) [](https://travis-ci.org/ahmetalpbalkan/go-linq) [](https://coveralls.io/github/ahmetalpbalkan/go-linq?branch=master) [](https://goreportcard.com/report/github.com/ahmetalpbalkan/go-linq)
|
||||||
A powerful language integrated query (LINQ) library for Go.
|
A powerful language integrated query (LINQ) library for Go.
|
||||||
* Written in vanilla Go!
|
* Written in vanilla Go, no dependencies!
|
||||||
* Safe for concurrent use
|
|
||||||
* Complete lazy evaluation with iterator pattern
|
* Complete lazy evaluation with iterator pattern
|
||||||
|
* Safe for concurrent use
|
||||||
|
* Supports generic functions to make your code cleaner and free of type assertions
|
||||||
* Supports arrays, slices, maps, strings, channels and custom collections
|
* Supports arrays, slices, maps, strings, channels and custom collections
|
||||||
(collection needs to implement `Iterable` interface and element - `Comparable`
|
|
||||||
interface)
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
$ go get github.com/ahmetalpbalkan/go-linq
|
$ go get github.com/ahmetalpbalkan/go-linq
|
||||||
|
|
||||||
|
We recommend using a dependency manager (e.g. [govendor][govendor] or
|
||||||
|
[godep][godep]) to maintain a local copy of this package in your project.
|
||||||
|
|
||||||
|
[govendor]: https://github.com/kardianos/govendor
|
||||||
|
[godep]: https://github.com/tools/godep/
|
||||||
|
|
||||||
> :warning: :warning: `go-linq` has recently introduced _breaking API changes_
|
> :warning: :warning: `go-linq` has recently introduced _breaking API changes_
|
||||||
> with v2.0.0. See [release notes](#release-notes) for details. v2.0.0 comes with
|
> with v2.0.0. See [release notes](#release-notes) for details. v2.0.0 comes with
|
||||||
> a refined interface, dramatically increased performance and memory efficiency,
|
> a refined interface, dramatically increased performance and memory efficiency,
|
||||||
@@ -26,16 +31,20 @@ Usage is as easy as chaining methods like:
|
|||||||
|
|
||||||
`From(slice)` `.Where(predicate)` `.Select(selector)` `.Union(data)`
|
`From(slice)` `.Where(predicate)` `.Select(selector)` `.Union(data)`
|
||||||
|
|
||||||
**Example: Find all owners of cars manufactured from 2015**
|
**Example 1: Find all owners of cars manufactured after 2015**
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import . "github.com/ahmetalpbalkan/go-linq"
|
import . "github.com/ahmetalpbalkan/go-linq"
|
||||||
|
|
||||||
type Car struct {
|
type Car struct {
|
||||||
id, year int
|
year int
|
||||||
owner, model string
|
owner, model string
|
||||||
}
|
}
|
||||||
|
|
||||||
owners := []string{}
|
...
|
||||||
|
|
||||||
|
|
||||||
|
var owners []string
|
||||||
|
|
||||||
From(cars).Where(func(c interface{}) bool {
|
From(cars).Where(func(c interface{}) bool {
|
||||||
return c.(Car).year >= 2015
|
return c.(Car).year >= 2015
|
||||||
@@ -44,7 +53,21 @@ From(cars).Where(func(c interface{}) bool {
|
|||||||
}).ToSlice(&owners)
|
}).ToSlice(&owners)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example: Find the author who has written the most books**
|
Or, you can use generic functions, like `WhereT` and `SelectT` to simplify your code
|
||||||
|
(at a performance penalty):
|
||||||
|
|
||||||
|
```go
|
||||||
|
var owners []string
|
||||||
|
|
||||||
|
From(cars).WhereT(func(c Car) bool {
|
||||||
|
return c.year >= 2015
|
||||||
|
}).SelectT(func(c Car) string {
|
||||||
|
return c.owner
|
||||||
|
}).ToSlice(&owners)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example 2: Find the author who has written the most books**
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import . "github.com/ahmetalpbalkan/go-linq"
|
import . "github.com/ahmetalpbalkan/go-linq"
|
||||||
|
|
||||||
@@ -71,7 +94,8 @@ author := From(books).SelectMany( // make a flat array of authors
|
|||||||
}).First() // take the first author
|
}).First() // take the first author
|
||||||
```
|
```
|
||||||
|
|
||||||
**Example: Implement a custom method that leaves only values greater than the specified threshold**
|
**Example 3: Implement a custom method that leaves only values greater than the specified threshold**
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type MyQuery Query
|
type MyQuery Query
|
||||||
|
|
||||||
@@ -96,10 +120,67 @@ func (q MyQuery) GreaterThan(threshold int) Query {
|
|||||||
result := MyQuery(Range(1,10)).GreaterThan(5).Results()
|
result := MyQuery(Range(1,10)).GreaterThan(5).Results()
|
||||||
```
|
```
|
||||||
|
|
||||||
**More examples** can be found in [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq).
|
## Generic Functions
|
||||||
|
|
||||||
|
Although Go doesn't implement generics, with some reflection tricks, you can use go-linq without
|
||||||
|
typing `interface{}`s and type assertions. This will introduce a performance penalty (5x-10x slower)
|
||||||
|
but will yield in a cleaner and more readable code.
|
||||||
|
|
||||||
|
Methods with `T` suffix (such as `WhereT`) accept functions with generic types. So instead of
|
||||||
|
|
||||||
|
.Select(func(v interface{}) interface{} {...})
|
||||||
|
|
||||||
|
you can type:
|
||||||
|
|
||||||
|
.SelectT(func(v YourType) YourOtherType {...})
|
||||||
|
|
||||||
|
This will make your code free of `interface{}` and type assertions.
|
||||||
|
|
||||||
|
**Example 4: "MapReduce" in a slice of string sentences to list the top 5 most used words using generic functions**
|
||||||
|
|
||||||
|
```go
|
||||||
|
var results []string
|
||||||
|
|
||||||
|
From(sentences).
|
||||||
|
// split sentences to words
|
||||||
|
SelectManyT(func(sentence string) Query {
|
||||||
|
return From(strings.Split(sentence, " "))
|
||||||
|
}).
|
||||||
|
// group the words
|
||||||
|
GroupByT(
|
||||||
|
func(word string) string { return word },
|
||||||
|
func(word string) string { return word },
|
||||||
|
).
|
||||||
|
// order by count
|
||||||
|
OrderByDescendingT(func(wordGroup Group) int {
|
||||||
|
return len(wordGroup.Group)
|
||||||
|
}).
|
||||||
|
// order by the word
|
||||||
|
ThenByT(func(wordGroup Group) string {
|
||||||
|
return wordGroup.Key.(string)
|
||||||
|
}).
|
||||||
|
Take(5). // take the top 5
|
||||||
|
// project the words using the index as rank
|
||||||
|
SelectIndexedT(func(index int, wordGroup Group) string {
|
||||||
|
return fmt.Sprintf("Rank: #%d, Word: %s, Counts: %d", index+1, wordGroup.Key, len(wordGroup.Group))
|
||||||
|
}).
|
||||||
|
ToSlice(&results)
|
||||||
|
```
|
||||||
|
|
||||||
|
**More examples** can be found in the [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq).
|
||||||
|
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
~~~
|
~~~
|
||||||
|
v3.0.0 (2017-01-10)
|
||||||
|
* Breaking change: ToSlice() now overwrites existing slice starting
|
||||||
|
from index 0 and grows/reslices it as needed.
|
||||||
|
* Generic methods support (thanks @cleitonmarx!)
|
||||||
|
- Accepting parametrized functions was originally proposed in #26
|
||||||
|
- You can now avoid type assertions and interface{}s
|
||||||
|
- Functions with generic methods are named as "MethodNameT" and
|
||||||
|
signature for the existing LINQ methods are unchanged.
|
||||||
|
* Added ForEach(), ForEachIndexed() and AggregateWithSeedBy().
|
||||||
|
|
||||||
v2.0.0 (2016-09-02)
|
v2.0.0 (2016-09-02)
|
||||||
* IMPORTANT: This release is a BREAKING CHANGE. The old version
|
* IMPORTANT: This release is a BREAKING CHANGE. The old version
|
||||||
|
|||||||
+124
-19
@@ -2,16 +2,15 @@ package linq
|
|||||||
|
|
||||||
// Aggregate applies an accumulator function over a sequence.
|
// Aggregate applies an accumulator function over a sequence.
|
||||||
//
|
//
|
||||||
// Aggregate method makes it simple to perform a calculation over a sequence of values.
|
// Aggregate method makes it simple to perform a calculation over a sequence of
|
||||||
// This method works by calling f() one time for each element in source
|
// values. This method works by calling f() one time for each element in source
|
||||||
// except the first one. Each time f() is called, Aggregate passes both
|
// except the first one. Each time f() is called, Aggregate passes both the
|
||||||
// the element from the sequence and an aggregated value (as the first argument to f()).
|
// element from the sequence and an aggregated value (as the first argument to
|
||||||
// The first element of source is used as the initial aggregate value.
|
// f()). The first element of source is used as the initial aggregate value. The
|
||||||
// The result of f() replaces the previous aggregated value.
|
// result of f() replaces the previous aggregated value.
|
||||||
//
|
//
|
||||||
// Aggregate returns the final result of f().
|
// Aggregate returns the final result of f().
|
||||||
func (q Query) Aggregate(
|
func (q Query) Aggregate(f func(interface{}, interface{}) interface{}) interface{} {
|
||||||
f func(interface{}, interface{}) interface{}) interface{} {
|
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
|
|
||||||
result, any := next()
|
result, any := next()
|
||||||
@@ -26,21 +25,40 @@ func (q Query) Aggregate(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// AggregateWithSeed applies an accumulator function over a sequence.
|
// AggregateT is the typed version of Aggregate.
|
||||||
// The specified seed value is used as the initial accumulator value.
|
|
||||||
//
|
//
|
||||||
// Aggregate method makes it simple to perform a calculation over a sequence of values.
|
// - f is of type: func(TSource, TSource) TSource
|
||||||
// This method works by calling f() one time for each element in source
|
//
|
||||||
// except the first one. Each time f() is called, Aggregate passes both
|
// NOTE: Aggregate has better performance than AggregateT.
|
||||||
// the element from the sequence and an aggregated value (as the first argument to f()).
|
func (q Query) AggregateT(f interface{}) interface{} {
|
||||||
// The value of the seed parameter is used as the initial aggregate value.
|
fGenericFunc, err := newGenericFunc(
|
||||||
|
"AggregateT", "f", f,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fFunc := func(result interface{}, current interface{}) interface{} {
|
||||||
|
return fGenericFunc.Call(result, current)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.Aggregate(fFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AggregateWithSeed applies an accumulator function over a sequence. The
|
||||||
|
// specified seed value is used as the initial accumulator value.
|
||||||
|
//
|
||||||
|
// Aggregate method makes it simple to perform a calculation over a sequence of
|
||||||
|
// values. This method works by calling f() one time for each element in source
|
||||||
|
// except the first one. Each time f() is called, Aggregate passes both the
|
||||||
|
// element from the sequence and an aggregated value (as the first argument to
|
||||||
|
// f()). The value of the seed parameter is used as the initial aggregate value.
|
||||||
// The result of f() replaces the previous aggregated value.
|
// The result of f() replaces the previous aggregated value.
|
||||||
//
|
//
|
||||||
// Aggregate returns the final result of f().
|
// Aggregate returns the final result of f().
|
||||||
func (q Query) AggregateWithSeed(
|
func (q Query) AggregateWithSeed(seed interface{},
|
||||||
seed interface{},
|
f func(interface{}, interface{}) interface{}) interface{} {
|
||||||
f func(interface{}, interface{}) interface{},
|
|
||||||
) interface{} {
|
|
||||||
|
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
result := seed
|
result := seed
|
||||||
@@ -51,3 +69,90 @@ func (q Query) AggregateWithSeed(
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AggregateWithSeedT is the typed version of AggregateWithSeed.
|
||||||
|
//
|
||||||
|
// - f is of type "func(TAccumulate, TSource) TAccumulate"
|
||||||
|
//
|
||||||
|
// NOTE: AggregateWithSeed has better performance than
|
||||||
|
// AggregateWithSeedT.
|
||||||
|
func (q Query) AggregateWithSeedT(seed interface{},
|
||||||
|
f interface{}) interface{} {
|
||||||
|
fGenericFunc, err := newGenericFunc(
|
||||||
|
"AggregateWithSeed", "f", f,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fFunc := func(result interface{}, current interface{}) interface{} {
|
||||||
|
return fGenericFunc.Call(result, current)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.AggregateWithSeed(seed, fFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AggregateWithSeedBy applies an accumulator function over a sequence. The
|
||||||
|
// specified seed value is used as the initial accumulator value, and the
|
||||||
|
// specified function is used to select the result value.
|
||||||
|
//
|
||||||
|
// Aggregate method makes it simple to perform a calculation over a sequence of
|
||||||
|
// values. This method works by calling f() one time for each element in source.
|
||||||
|
// Each time func is called, Aggregate passes both the element from the sequence
|
||||||
|
// and an aggregated value (as the first argument to func). The value of the
|
||||||
|
// seed parameter is used as the initial aggregate value. The result of func
|
||||||
|
// replaces the previous aggregated value.
|
||||||
|
//
|
||||||
|
// The final result of func is passed to resultSelector to obtain the final
|
||||||
|
// result of Aggregate.
|
||||||
|
func (q Query) AggregateWithSeedBy(seed interface{},
|
||||||
|
f func(interface{}, interface{}) interface{},
|
||||||
|
resultSelector func(interface{}) interface{}) interface{} {
|
||||||
|
|
||||||
|
next := q.Iterate()
|
||||||
|
result := seed
|
||||||
|
|
||||||
|
for current, ok := next(); ok; current, ok = next() {
|
||||||
|
result = f(result, current)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultSelector(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AggregateWithSeedByT is the typed version of AggregateWithSeedBy.
|
||||||
|
//
|
||||||
|
// - f is of type "func(TAccumulate, TSource) TAccumulate"
|
||||||
|
// - resultSelectorFn is of type "func(TAccumulate) TResult"
|
||||||
|
//
|
||||||
|
// NOTE: AggregateWithSeedBy has better performance than
|
||||||
|
// AggregateWithSeedByT.
|
||||||
|
func (q Query) AggregateWithSeedByT(seed interface{},
|
||||||
|
f interface{},
|
||||||
|
resultSelectorFn interface{}) interface{} {
|
||||||
|
fGenericFunc, err := newGenericFunc(
|
||||||
|
"AggregateWithSeedByT", "f", f,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fFunc := func(result interface{}, current interface{}) interface{} {
|
||||||
|
return fGenericFunc.Call(result, current)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"AggregateWithSeedByT", "resultSelectorFn", resultSelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorFunc := func(result interface{}) interface{} {
|
||||||
|
return resultSelectorGenericFunc.Call(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.AggregateWithSeedBy(seed, fFunc, resultSelectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+2
-2
@@ -2,8 +2,8 @@ package linq
|
|||||||
|
|
||||||
type comparer func(interface{}, interface{}) int
|
type comparer func(interface{}, interface{}) int
|
||||||
|
|
||||||
// Comparable is an interface that has to be implemented by a
|
// Comparable is an interface that has to be implemented by a custom collection
|
||||||
// custom collection elememts in order to work with linq.
|
// elememts in order to work with linq.
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
// func (f foo) CompareTo(c Comparable) int {
|
// func (f foo) CompareTo(c Comparable) int {
|
||||||
|
|||||||
+6
-6
@@ -1,7 +1,7 @@
|
|||||||
package linq
|
package linq
|
||||||
|
|
||||||
// Append inserts an item to the end of a collection,
|
// Append inserts an item to the end of a collection, so it becomes the last
|
||||||
// so it becomes the last item.
|
// item.
|
||||||
func (q Query) Append(item interface{}) Query {
|
func (q Query) Append(item interface{}) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -28,8 +28,8 @@ func (q Query) Append(item interface{}) Query {
|
|||||||
// Concat concatenates two collections.
|
// Concat concatenates two collections.
|
||||||
//
|
//
|
||||||
// The Concat method differs from the Union method because the Concat method
|
// The Concat method differs from the Union method because the Concat method
|
||||||
// returns all the original elements in the input sequences.
|
// returns all the original elements in the input sequences. The Union method
|
||||||
// The Union method returns only unique elements.
|
// returns only unique elements.
|
||||||
func (q Query) Concat(q2 Query) Query {
|
func (q Query) Concat(q2 Query) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -53,8 +53,8 @@ func (q Query) Concat(q2 Query) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepend inserts an item to the beginning of a collection,
|
// Prepend inserts an item to the beginning of a collection, so it becomes the
|
||||||
// so it becomes the first item.
|
// first item.
|
||||||
func (q Query) Prepend(item interface{}) Query {
|
func (q Query) Prepend(item interface{}) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
|
|||||||
+28
-5
@@ -1,7 +1,7 @@
|
|||||||
package linq
|
package linq
|
||||||
|
|
||||||
// Distinct method returns distinct elements from a collection.
|
// Distinct method returns distinct elements from a collection. The result is an
|
||||||
// The result is an unordered collection that contains no duplicate values.
|
// unordered collection that contains no duplicate values.
|
||||||
func (q Query) Distinct() Query {
|
func (q Query) Distinct() Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -22,11 +22,11 @@ func (q Query) Distinct() Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Distinct method returns distinct elements from a collection.
|
// Distinct method returns distinct elements from a collection. The result is an
|
||||||
// The result is an ordered collection that contains no duplicate values.
|
// ordered collection that contains no duplicate values.
|
||||||
//
|
//
|
||||||
// NOTE: Distinct method on OrderedQuery type has better performance than
|
// NOTE: Distinct method on OrderedQuery type has better performance than
|
||||||
// Distinct method on Query type
|
// Distinct method on Query type.
|
||||||
func (oq OrderedQuery) Distinct() OrderedQuery {
|
func (oq OrderedQuery) Distinct() OrderedQuery {
|
||||||
return OrderedQuery{
|
return OrderedQuery{
|
||||||
orders: oq.orders,
|
orders: oq.orders,
|
||||||
@@ -73,3 +73,26 @@ func (q Query) DistinctBy(selector func(interface{}) interface{}) Query {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DistinctByT is the typed version of DistinctBy.
|
||||||
|
//
|
||||||
|
// - selectorFn is of type "func(TSource) TSource".
|
||||||
|
//
|
||||||
|
// NOTE: DistinctBy has better performance than DistinctByT.
|
||||||
|
func (q Query) DistinctByT(selectorFn interface{}) Query {
|
||||||
|
selectorFunc, ok := selectorFn.(func(interface{}) interface{})
|
||||||
|
if !ok {
|
||||||
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"DistinctByT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc = func(item interface{}) interface{} {
|
||||||
|
return selectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q.DistinctBy(selectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+4
-3
@@ -1,5 +1,6 @@
|
|||||||
// Package linq provides methods for querying and manipulating
|
// Package linq provides methods for querying and manipulating slices, arrays,
|
||||||
// slices, arrays, maps, strings, channels and collections.
|
// maps, strings, channels and collections.
|
||||||
//
|
//
|
||||||
// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan
|
// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan, Cleiton Marques
|
||||||
|
// Souza.
|
||||||
package linq
|
package linq
|
||||||
|
|||||||
+29
-9
@@ -1,8 +1,7 @@
|
|||||||
package linq
|
package linq
|
||||||
|
|
||||||
// Except produces the set difference of two sequences.
|
// Except produces the set difference of two sequences. The set difference is
|
||||||
// The set difference is the members of the first sequence
|
// the members of the first sequence that don't appear in the second sequence.
|
||||||
// that don't appear in the second sequence.
|
|
||||||
func (q Query) Except(q2 Query) Query {
|
func (q Query) Except(q2 Query) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -27,12 +26,11 @@ func (q Query) Except(q2 Query) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExceptBy invokes a transform function on each element of a collection
|
// ExceptBy invokes a transform function on each element of a collection and
|
||||||
// and produces the set difference of two sequences.
|
// produces the set difference of two sequences. The set difference is the
|
||||||
// The set difference is the members of the first sequence
|
// members of the first sequence that don't appear in the second sequence.
|
||||||
// that don't appear in the second sequence.
|
func (q Query) ExceptBy(q2 Query,
|
||||||
func (q Query) ExceptBy(
|
selector func(interface{}) interface{}) Query {
|
||||||
q2 Query, selector func(interface{}) interface{}) Query {
|
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
@@ -57,3 +55,25 @@ func (q Query) ExceptBy(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExceptByT is the typed version of ExceptBy.
|
||||||
|
//
|
||||||
|
// - selectorFn is of type "func(TSource) TSource"
|
||||||
|
//
|
||||||
|
// NOTE: ExceptBy has better performance than ExceptByT.
|
||||||
|
func (q Query) ExceptByT(q2 Query,
|
||||||
|
selectorFn interface{}) Query {
|
||||||
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"ExceptByT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(item interface{}) interface{} {
|
||||||
|
return selectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.ExceptBy(q2, selectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+17
-17
@@ -5,30 +5,30 @@ import "reflect"
|
|||||||
// Iterator is an alias for function to iterate over data.
|
// Iterator is an alias for function to iterate over data.
|
||||||
type Iterator func() (item interface{}, ok bool)
|
type Iterator func() (item interface{}, ok bool)
|
||||||
|
|
||||||
// Query is the type returned from query functions.
|
// Query is the type returned from query functions. It can be iterated manually
|
||||||
// It can be iterated manually as shown in the example.
|
// as shown in the example.
|
||||||
type Query struct {
|
type Query struct {
|
||||||
Iterate func() Iterator
|
Iterate func() Iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyValue is a type that is used to iterate over a map
|
// KeyValue is a type that is used to iterate over a map (if query is created
|
||||||
// (if query is created from a map). This type is also used by
|
// from a map). This type is also used by ToMap() method to output result of a
|
||||||
// ToMap() method to output result of a query into a map.
|
// query into a map.
|
||||||
type KeyValue struct {
|
type KeyValue struct {
|
||||||
Key interface{}
|
Key interface{}
|
||||||
Value interface{}
|
Value interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterable is an interface that has to be implemented by a
|
// Iterable is an interface that has to be implemented by a custom collection in
|
||||||
// custom collection in order to work with linq.
|
// order to work with linq.
|
||||||
type Iterable interface {
|
type Iterable interface {
|
||||||
Iterate() Iterator
|
Iterate() Iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
// From initializes a linq query with passed slice, array or map
|
// From initializes a linq query with passed slice, array or map as the source.
|
||||||
// as the source. String, channel or struct implementing Iterable
|
// String, channel or struct implementing Iterable interface can be used as an
|
||||||
// interface can be used as an input. In this case From delegates it
|
// input. In this case From delegates it to FromString, FromChannel and
|
||||||
// to FromString, FromChannel and FromIterable internally.
|
// FromIterable internally.
|
||||||
func From(source interface{}) Query {
|
func From(source interface{}) Query {
|
||||||
src := reflect.ValueOf(source)
|
src := reflect.ValueOf(source)
|
||||||
|
|
||||||
@@ -84,8 +84,8 @@ func From(source interface{}) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromChannel initializes a linq query with passed channel,
|
// FromChannel initializes a linq query with passed channel, linq iterates over
|
||||||
// linq iterates over channel until it is closed.
|
// channel until it is closed.
|
||||||
func FromChannel(source <-chan interface{}) Query {
|
func FromChannel(source <-chan interface{}) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -97,8 +97,8 @@ func FromChannel(source <-chan interface{}) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromString initializes a linq query with passed string,
|
// FromString initializes a linq query with passed string, linq iterates over
|
||||||
// linq iterates over runes of string.
|
// runes of string.
|
||||||
func FromString(source string) Query {
|
func FromString(source string) Query {
|
||||||
runes := []rune(source)
|
runes := []rune(source)
|
||||||
len := len(runes)
|
len := len(runes)
|
||||||
@@ -120,8 +120,8 @@ func FromString(source string) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromIterable initializes a linq query with custom collection passed.
|
// FromIterable initializes a linq query with custom collection passed. This
|
||||||
// This collection has to implement Iterable interface, linq iterates over items,
|
// collection has to implement Iterable interface, linq iterates over items,
|
||||||
// that has to implement Comparable interface or be basic types.
|
// that has to implement Comparable interface or be basic types.
|
||||||
func FromIterable(source Iterable) Query {
|
func FromIterable(source Iterable) Query {
|
||||||
return Query{
|
return Query{
|
||||||
|
|||||||
+41
-8
@@ -6,14 +6,11 @@ type Group struct {
|
|||||||
Group []interface{}
|
Group []interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GroupBy method groups the elements of a collection according
|
// GroupBy method groups the elements of a collection according to a specified
|
||||||
// to a specified key selector function and projects the elements for each group
|
// key selector function and projects the elements for each group by using a
|
||||||
// by using a specified function.
|
// specified function.
|
||||||
func (q Query) GroupBy(
|
func (q Query) GroupBy(keySelector func(interface{}) interface{},
|
||||||
keySelector func(interface{}) interface{},
|
elementSelector func(interface{}) interface{}) Query {
|
||||||
elementSelector func(interface{}) interface{},
|
|
||||||
) Query {
|
|
||||||
|
|
||||||
return Query{
|
return Query{
|
||||||
func() Iterator {
|
func() Iterator {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
@@ -46,3 +43,39 @@ func (q Query) GroupBy(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupByT is the typed version of GroupBy.
|
||||||
|
//
|
||||||
|
// - keySelectorFn is of type "func(TSource) TKey"
|
||||||
|
// - elementSelectorFn is of type "func(TSource) TElement"
|
||||||
|
//
|
||||||
|
// NOTE: GroupBy has better performance than GroupByT.
|
||||||
|
func (q Query) GroupByT(keySelectorFn interface{},
|
||||||
|
elementSelectorFn interface{}) Query {
|
||||||
|
keySelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"GroupByT", "keySelectorFn", keySelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
keySelectorFunc := func(item interface{}) interface{} {
|
||||||
|
return keySelectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
elementSelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"GroupByT", "elementSelectorFn", elementSelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
elementSelectorFunc := func(item interface{}) interface{} {
|
||||||
|
return elementSelectorGenericFunc.Call(item)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.GroupBy(keySelectorFunc, elementSelectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+69
-12
@@ -1,25 +1,27 @@
|
|||||||
package linq
|
package linq
|
||||||
|
|
||||||
|
import "reflect"
|
||||||
|
|
||||||
// GroupJoin correlates the elements of two collections based on key equality,
|
// GroupJoin correlates the elements of two collections based on key equality,
|
||||||
// and groups the results.
|
// and groups the results.
|
||||||
//
|
//
|
||||||
// This method produces hierarchical results, which means that elements from outer query
|
// This method produces hierarchical results, which means that elements from
|
||||||
// are paired with collections of matching elements from inner. GroupJoin enables you
|
// outer query are paired with collections of matching elements from inner.
|
||||||
// to base your results on a whole set of matches for each element of outer query.
|
// GroupJoin enables you to base your results on a whole set of matches for each
|
||||||
|
// element of outer query.
|
||||||
//
|
//
|
||||||
// The resultSelector function is called only one time for each outer element
|
// The resultSelector function is called only one time for each outer element
|
||||||
// together with a collection of all the inner elements that match the outer element.
|
// together with a collection of all the inner elements that match the outer
|
||||||
// This differs from the Join method, in which the result selector function is invoked
|
// element. This differs from the Join method, in which the result selector
|
||||||
// on pairs that contain one element from outer and one element from inner.
|
// function is invoked on pairs that contain one element from outer and one
|
||||||
|
// element from inner.
|
||||||
//
|
//
|
||||||
// GroupJoin preserves the order of the elements of outer, and for each element of outer,
|
// GroupJoin preserves the order of the elements of outer, and for each element
|
||||||
// the order of the matching elements from inner.
|
// of outer, the order of the matching elements from inner.
|
||||||
func (q Query) GroupJoin(
|
func (q Query) GroupJoin(inner Query,
|
||||||
inner Query,
|
|
||||||
outerKeySelector func(interface{}) interface{},
|
outerKeySelector func(interface{}) interface{},
|
||||||
innerKeySelector func(interface{}) interface{},
|
innerKeySelector func(interface{}) interface{},
|
||||||
resultSelector func(outer interface{}, inners []interface{}) interface{},
|
resultSelector func(outer interface{}, inners []interface{}) interface{}) Query {
|
||||||
) Query {
|
|
||||||
|
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -48,3 +50,58 @@ func (q Query) GroupJoin(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GroupJoinT is the typed version of GroupJoin.
|
||||||
|
//
|
||||||
|
// - inner: The query to join to the outer query.
|
||||||
|
// - outerKeySelectorFn is of type "func(TOuter) TKey"
|
||||||
|
// - innerKeySelectorFn is of type "func(TInner) TKey"
|
||||||
|
// - resultSelectorFn: is of type "func(TOuter, inners []TInner) TResult"
|
||||||
|
//
|
||||||
|
// NOTE: GroupJoin has better performance than GroupJoinT.
|
||||||
|
func (q Query) GroupJoinT(inner Query,
|
||||||
|
outerKeySelectorFn interface{},
|
||||||
|
innerKeySelectorFn interface{},
|
||||||
|
resultSelectorFn interface{}) Query {
|
||||||
|
outerKeySelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"GroupJoinT", "outerKeySelectorFn", outerKeySelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outerKeySelectorFunc := func(item interface{}) interface{} {
|
||||||
|
return outerKeySelectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
innerKeySelectorFuncGenericFunc, err := newGenericFunc(
|
||||||
|
"GroupJoinT", "innerKeySelectorFn", innerKeySelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
innerKeySelectorFunc := func(item interface{}) interface{} {
|
||||||
|
return innerKeySelectorFuncGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"GroupJoinT", "resultSelectorFn", resultSelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorFunc := func(outer interface{}, inners []interface{}) interface{} {
|
||||||
|
innerSliceType := reflect.MakeSlice(resultSelectorGenericFunc.Cache.TypesIn[1], 0, 0)
|
||||||
|
innersSlicePointer := reflect.New(innerSliceType.Type())
|
||||||
|
From(inners).ToSlice(innersSlicePointer.Interface())
|
||||||
|
innersTyped := reflect.Indirect(innersSlicePointer).Interface()
|
||||||
|
return resultSelectorGenericFunc.Call(outer, innersTyped)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.GroupJoin(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+28
-8
@@ -2,8 +2,8 @@ package linq
|
|||||||
|
|
||||||
// Intersect produces the set intersection of the source collection and the
|
// Intersect produces the set intersection of the source collection and the
|
||||||
// provided input collection. The intersection of two sets A and B is defined as
|
// provided input collection. The intersection of two sets A and B is defined as
|
||||||
// the set that contains all the elements of A that also appear in B,
|
// the set that contains all the elements of A that also appear in B, but no
|
||||||
// but no other elements.
|
// other elements.
|
||||||
func (q Query) Intersect(q2 Query) Query {
|
func (q Query) Intersect(q2 Query) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -31,14 +31,12 @@ func (q Query) Intersect(q2 Query) Query {
|
|||||||
|
|
||||||
// IntersectBy produces the set intersection of the source collection and the
|
// IntersectBy produces the set intersection of the source collection and the
|
||||||
// provided input collection. The intersection of two sets A and B is defined as
|
// provided input collection. The intersection of two sets A and B is defined as
|
||||||
// the set that contains all the elements of A that also appear in B,
|
// the set that contains all the elements of A that also appear in B, but no
|
||||||
// but no other elements.
|
// other elements.
|
||||||
//
|
//
|
||||||
// IntersectBy invokes a transform function on each element of both collections.
|
// IntersectBy invokes a transform function on each element of both collections.
|
||||||
func (q Query) IntersectBy(
|
func (q Query) IntersectBy(q2 Query,
|
||||||
q2 Query,
|
selector func(interface{}) interface{}) Query {
|
||||||
selector func(interface{}) interface{},
|
|
||||||
) Query {
|
|
||||||
|
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -65,3 +63,25 @@ func (q Query) IntersectBy(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IntersectByT is the typed version of IntersectBy.
|
||||||
|
//
|
||||||
|
// - selectorFn is of type "func(TSource) TSource"
|
||||||
|
//
|
||||||
|
// NOTE: IntersectBy has better performance than IntersectByT.
|
||||||
|
func (q Query) IntersectByT(q2 Query,
|
||||||
|
selectorFn interface{}) Query {
|
||||||
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"IntersectByT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(item interface{}) interface{} {
|
||||||
|
return selectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.IntersectBy(q2, selectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+59
-10
@@ -2,20 +2,18 @@ package linq
|
|||||||
|
|
||||||
// Join correlates the elements of two collection based on matching keys.
|
// Join correlates the elements of two collection based on matching keys.
|
||||||
//
|
//
|
||||||
// A join refers to the operation of correlating the elements of two sources
|
// A join refers to the operation of correlating the elements of two sources of
|
||||||
// of information based on a common key. Join brings the two information sources
|
// information based on a common key. Join brings the two information sources
|
||||||
// and the keys by which they are matched together in one method call.
|
// and the keys by which they are matched together in one method call. This
|
||||||
// This differs from the use of SelectMany, which requires more than one method call
|
// differs from the use of SelectMany, which requires more than one method call
|
||||||
// to perform the same operation.
|
// to perform the same operation.
|
||||||
//
|
//
|
||||||
// Join preserves the order of the elements of outer collection,
|
// Join preserves the order of the elements of outer collection, and for each of
|
||||||
// and for each of these elements, the order of the matching elements of inner.
|
// these elements, the order of the matching elements of inner.
|
||||||
func (q Query) Join(
|
func (q Query) Join(inner Query,
|
||||||
inner Query,
|
|
||||||
outerKeySelector func(interface{}) interface{},
|
outerKeySelector func(interface{}) interface{},
|
||||||
innerKeySelector func(interface{}) interface{},
|
innerKeySelector func(interface{}) interface{},
|
||||||
resultSelector func(outer interface{}, inner interface{}) interface{},
|
resultSelector func(outer interface{}, inner interface{}) interface{}) Query {
|
||||||
) Query {
|
|
||||||
|
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -54,3 +52,54 @@ func (q Query) Join(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JoinT is the typed version of Join.
|
||||||
|
//
|
||||||
|
// - outerKeySelectorFn is of type "func(TOuter) TKey"
|
||||||
|
// - innerKeySelectorFn is of type "func(TInner) TKey"
|
||||||
|
// - resultSelectorFn is of type "func(TOuter,TInner) TResult"
|
||||||
|
//
|
||||||
|
// NOTE: Join has better performance than JoinT.
|
||||||
|
func (q Query) JoinT(inner Query,
|
||||||
|
outerKeySelectorFn interface{},
|
||||||
|
innerKeySelectorFn interface{},
|
||||||
|
resultSelectorFn interface{}) Query {
|
||||||
|
outerKeySelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"JoinT", "outerKeySelectorFn", outerKeySelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
outerKeySelectorFunc := func(item interface{}) interface{} {
|
||||||
|
return outerKeySelectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
innerKeySelectorFuncGenericFunc, err := newGenericFunc(
|
||||||
|
"JoinT", "innerKeySelectorFn",
|
||||||
|
innerKeySelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
innerKeySelectorFunc := func(item interface{}) interface{} {
|
||||||
|
return innerKeySelectorFuncGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"JoinT", "resultSelectorFn", resultSelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorFunc := func(outer interface{}, inner interface{}) interface{} {
|
||||||
|
return resultSelectorGenericFunc.Call(outer, inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.Join(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+121
-20
@@ -8,18 +8,17 @@ type order struct {
|
|||||||
desc bool
|
desc bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrderedQuery is the type returned from OrderBy, OrderByDescending
|
// OrderedQuery is the type returned from OrderBy, OrderByDescending ThenBy and
|
||||||
// ThenBy and ThenByDescending functions.
|
// ThenByDescending functions.
|
||||||
type OrderedQuery struct {
|
type OrderedQuery struct {
|
||||||
Query
|
Query
|
||||||
original Query
|
original Query
|
||||||
orders []order
|
orders []order
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrderBy sorts the elements of a collection in ascending order.
|
// OrderBy sorts the elements of a collection in ascending order. Elements are
|
||||||
// Elements are sorted according to a key.
|
// sorted according to a key.
|
||||||
func (q Query) OrderBy(
|
func (q Query) OrderBy(selector func(interface{}) interface{}) OrderedQuery {
|
||||||
selector func(interface{}) interface{}) OrderedQuery {
|
|
||||||
return OrderedQuery{
|
return OrderedQuery{
|
||||||
orders: []order{{selector: selector}},
|
orders: []order{{selector: selector}},
|
||||||
original: q,
|
original: q,
|
||||||
@@ -43,10 +42,30 @@ func (q Query) OrderBy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OrderByT is the typed version of OrderBy.
|
||||||
|
//
|
||||||
|
// - selectorFn is of type "func(TSource) TKey"
|
||||||
|
//
|
||||||
|
// NOTE: OrderBy has better performance than OrderByT.
|
||||||
|
func (q Query) OrderByT(selectorFn interface{}) OrderedQuery {
|
||||||
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"OrderByT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(item interface{}) interface{} {
|
||||||
|
return selectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.OrderBy(selectorFunc)
|
||||||
|
}
|
||||||
|
|
||||||
// OrderByDescending sorts the elements of a collection in descending order.
|
// OrderByDescending sorts the elements of a collection in descending order.
|
||||||
// Elements are sorted according to a key.
|
// Elements are sorted according to a key.
|
||||||
func (q Query) OrderByDescending(
|
func (q Query) OrderByDescending(selector func(interface{}) interface{}) OrderedQuery {
|
||||||
selector func(interface{}) interface{}) OrderedQuery {
|
|
||||||
return OrderedQuery{
|
return OrderedQuery{
|
||||||
orders: []order{{selector: selector, desc: true}},
|
orders: []order{{selector: selector, desc: true}},
|
||||||
original: q,
|
original: q,
|
||||||
@@ -70,9 +89,28 @@ func (q Query) OrderByDescending(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ThenBy performs a subsequent ordering of the elements in a collection
|
// OrderByDescendingT is the typed version of OrderByDescending.
|
||||||
// in ascending order. This method enables you to specify multiple sort criteria
|
// - selectorFn is of type "func(TSource) TKey"
|
||||||
// by applying any number of ThenBy or ThenByDescending methods.
|
// NOTE: OrderByDescending has better performance than OrderByDescendingT.
|
||||||
|
func (q Query) OrderByDescendingT(selectorFn interface{}) OrderedQuery {
|
||||||
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"OrderByDescendingT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(item interface{}) interface{} {
|
||||||
|
return selectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.OrderByDescending(selectorFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThenBy performs a subsequent ordering of the elements in a collection in
|
||||||
|
// ascending order. This method enables you to specify multiple sort criteria by
|
||||||
|
// applying any number of ThenBy or ThenByDescending methods.
|
||||||
func (oq OrderedQuery) ThenBy(
|
func (oq OrderedQuery) ThenBy(
|
||||||
selector func(interface{}) interface{}) OrderedQuery {
|
selector func(interface{}) interface{}) OrderedQuery {
|
||||||
return OrderedQuery{
|
return OrderedQuery{
|
||||||
@@ -98,11 +136,29 @@ func (oq OrderedQuery) ThenBy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ThenByDescending performs a subsequent ordering of the elements in a collection
|
// ThenByT is the typed version of ThenBy.
|
||||||
// in descending order. This method enables you to specify multiple sort criteria
|
// - selectorFn is of type "func(TSource) TKey"
|
||||||
// by applying any number of ThenBy or ThenByDescending methods.
|
// NOTE: ThenBy has better performance than ThenByT.
|
||||||
func (oq OrderedQuery) ThenByDescending(
|
func (oq OrderedQuery) ThenByT(selectorFn interface{}) OrderedQuery {
|
||||||
selector func(interface{}) interface{}) OrderedQuery {
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"ThenByT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(item interface{}) interface{} {
|
||||||
|
return selectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return oq.ThenBy(selectorFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ThenByDescending performs a subsequent ordering of the elements in a
|
||||||
|
// collection in descending order. This method enables you to specify multiple
|
||||||
|
// sort criteria by applying any number of ThenBy or ThenByDescending methods.
|
||||||
|
func (oq OrderedQuery) ThenByDescending(selector func(interface{}) interface{}) OrderedQuery {
|
||||||
return OrderedQuery{
|
return OrderedQuery{
|
||||||
orders: append(oq.orders, order{selector: selector, desc: true}),
|
orders: append(oq.orders, order{selector: selector, desc: true}),
|
||||||
original: oq.original,
|
original: oq.original,
|
||||||
@@ -126,10 +182,32 @@ func (oq OrderedQuery) ThenByDescending(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort returns a new query by sorting elements with provided less function
|
// ThenByDescendingT is the typed version of ThenByDescending.
|
||||||
// in ascending order. The comparer function should return true if the parameter i
|
// - selectorFn is of type "func(TSource) TKey"
|
||||||
// is less than j. While this method is uglier than chaining OrderBy, OrderByDescending,
|
// NOTE: ThenByDescending has better performance than ThenByDescendingT.
|
||||||
// ThenBy and ThenByDescending methods, it's performance is much better.
|
func (oq OrderedQuery) ThenByDescendingT(selectorFn interface{}) OrderedQuery {
|
||||||
|
selectorFunc, ok := selectorFn.(func(interface{}) interface{})
|
||||||
|
if !ok {
|
||||||
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"ThenByDescending", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc = func(item interface{}) interface{} {
|
||||||
|
return selectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oq.ThenByDescending(selectorFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort returns a new query by sorting elements with provided less function in
|
||||||
|
// ascending order. The comparer function should return true if the parameter i
|
||||||
|
// is less than j. While this method is uglier than chaining OrderBy,
|
||||||
|
// OrderByDescending, ThenBy and ThenByDescending methods, it's performance is
|
||||||
|
// much better.
|
||||||
func (q Query) Sort(less func(i, j interface{}) bool) Query {
|
func (q Query) Sort(less func(i, j interface{}) bool) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -150,6 +228,25 @@ func (q Query) Sort(less func(i, j interface{}) bool) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SortT is the typed version of Sort.
|
||||||
|
// - lessFn is of type "func(TSource,TSource) bool"
|
||||||
|
// NOTE: Sort has better performance than SortT.
|
||||||
|
func (q Query) SortT(lessFn interface{}) Query {
|
||||||
|
lessGenericFunc, err := newGenericFunc(
|
||||||
|
"SortT", "lessFn", lessFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lessFunc := func(i, j interface{}) bool {
|
||||||
|
return lessGenericFunc.Call(i, j).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.Sort(lessFunc)
|
||||||
|
}
|
||||||
|
|
||||||
type sorter struct {
|
type sorter struct {
|
||||||
items []interface{}
|
items []interface{}
|
||||||
less func(i, j interface{}) bool
|
less func(i, j interface{}) bool
|
||||||
@@ -173,6 +270,10 @@ func (q Query) sort(orders []order) (r []interface{}) {
|
|||||||
r = append(r, item)
|
r = append(r, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(r) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for i, j := range orders {
|
for i, j := range orders {
|
||||||
orders[i].compare = getComparer(j.selector(r[0]))
|
orders[i].compare = getComparer(j.selector(r[0]))
|
||||||
}
|
}
|
||||||
|
|||||||
+297
-33
@@ -18,6 +18,27 @@ func (q Query) All(predicate func(interface{}) bool) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AllT is the typed version of All.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(TSource) bool"
|
||||||
|
//
|
||||||
|
// NOTE: All has better performance than AllT.
|
||||||
|
func (q Query) AllT(predicateFn interface{}) bool {
|
||||||
|
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"AllT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.All(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
// Any determines whether any element of a collection exists.
|
// Any determines whether any element of a collection exists.
|
||||||
func (q Query) Any() bool {
|
func (q Query) Any() bool {
|
||||||
_, ok := q.Iterate()()
|
_, ok := q.Iterate()()
|
||||||
@@ -37,6 +58,28 @@ func (q Query) AnyWith(predicate func(interface{}) bool) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnyWithT is the typed version of AnyWith.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(TSource) bool"
|
||||||
|
//
|
||||||
|
// NOTE: AnyWith has better performance than AnyWithT.
|
||||||
|
func (q Query) AnyWithT(predicateFn interface{}) bool {
|
||||||
|
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"AnyWithT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.AnyWith(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
// Average computes the average of a collection of numeric values.
|
// Average computes the average of a collection of numeric values.
|
||||||
func (q Query) Average() (r float64) {
|
func (q Query) Average() (r float64) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
@@ -104,8 +147,8 @@ func (q Query) Count() (r int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountWith returns a number that represents how many elements
|
// CountWith returns a number that represents how many elements in the specified
|
||||||
// in the specified collection satisfy a condition.
|
// collection satisfy a condition.
|
||||||
func (q Query) CountWith(predicate func(interface{}) bool) (r int) {
|
func (q Query) CountWith(predicate func(interface{}) bool) (r int) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
|
|
||||||
@@ -118,14 +161,36 @@ func (q Query) CountWith(predicate func(interface{}) bool) (r int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountWithT is the typed version of CountWith.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(TSource) bool"
|
||||||
|
//
|
||||||
|
// NOTE: CountWith has better performance than CountWithT.
|
||||||
|
func (q Query) CountWithT(predicateFn interface{}) int {
|
||||||
|
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"CountWithT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.CountWith(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
// First returns the first element of a collection.
|
// First returns the first element of a collection.
|
||||||
func (q Query) First() interface{} {
|
func (q Query) First() interface{} {
|
||||||
item, _ := q.Iterate()()
|
item, _ := q.Iterate()()
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
// FirstWith returns the first element of a collection that satisfies
|
// FirstWith returns the first element of a collection that satisfies a
|
||||||
// a specified condition.
|
// specified condition.
|
||||||
func (q Query) FirstWith(predicate func(interface{}) bool) interface{} {
|
func (q Query) FirstWith(predicate func(interface{}) bool) interface{} {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
|
|
||||||
@@ -138,6 +203,99 @@ func (q Query) FirstWith(predicate func(interface{}) bool) interface{} {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FirstWithT is the typed version of FirstWith.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(TSource) bool"
|
||||||
|
//
|
||||||
|
// NOTE: FirstWith has better performance than FirstWithT.
|
||||||
|
func (q Query) FirstWithT(predicateFn interface{}) interface{} {
|
||||||
|
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"FirstWithT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.FirstWith(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEach performs the specified action on each element of a collection.
|
||||||
|
func (q Query) ForEach(action func(interface{})) {
|
||||||
|
next := q.Iterate()
|
||||||
|
|
||||||
|
for item, ok := next(); ok; item, ok = next() {
|
||||||
|
action(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEachT is the typed version of ForEach.
|
||||||
|
//
|
||||||
|
// - actionFn is of type "func(TSource)"
|
||||||
|
//
|
||||||
|
// NOTE: ForEach has better performance than ForEachT.
|
||||||
|
func (q Query) ForEachT(actionFn interface{}) {
|
||||||
|
actionGenericFunc, err := newGenericFunc(
|
||||||
|
"ForEachT", "actionFn", actionFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), nil),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actionFunc := func(item interface{}) {
|
||||||
|
actionGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
q.ForEach(actionFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEachIndexed performs the specified action on each element of a collection.
|
||||||
|
//
|
||||||
|
// The first argument to action represents the zero-based index of that
|
||||||
|
// element in the source collection. This can be useful if the elements are in a
|
||||||
|
// known order and you want to do something with an element at a particular
|
||||||
|
// index, for example. It can also be useful if you want to retrieve the index
|
||||||
|
// of one or more elements. The second argument to action represents the
|
||||||
|
// element to process.
|
||||||
|
func (q Query) ForEachIndexed(action func(int, interface{})) {
|
||||||
|
next := q.Iterate()
|
||||||
|
index := 0
|
||||||
|
|
||||||
|
for item, ok := next(); ok; item, ok = next() {
|
||||||
|
action(index, item)
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEachIndexedT is the typed version of ForEachIndexed.
|
||||||
|
//
|
||||||
|
// - actionFn is of type "func(int, TSource)"
|
||||||
|
//
|
||||||
|
// NOTE: ForEachIndexed has better performance than ForEachIndexedT.
|
||||||
|
func (q Query) ForEachIndexedT(actionFn interface{}) {
|
||||||
|
actionGenericFunc, err := newGenericFunc(
|
||||||
|
"ForEachIndexedT", "actionFn", actionFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), nil),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actionFunc := func(index int, item interface{}) {
|
||||||
|
actionGenericFunc.Call(index, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
q.ForEachIndexed(actionFunc)
|
||||||
|
}
|
||||||
|
|
||||||
// Last returns the last element of a collection.
|
// Last returns the last element of a collection.
|
||||||
func (q Query) Last() (r interface{}) {
|
func (q Query) Last() (r interface{}) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
@@ -149,8 +307,8 @@ func (q Query) Last() (r interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// LastWith returns the last element of a collection that satisfies
|
// LastWith returns the last element of a collection that satisfies a specified
|
||||||
// a specified condition.
|
// condition.
|
||||||
func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) {
|
func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
|
|
||||||
@@ -163,6 +321,28 @@ func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LastWithT is the typed version of LastWith.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(TSource) bool"
|
||||||
|
//
|
||||||
|
// NOTE: LastWith has better performance than LastWithT.
|
||||||
|
func (q Query) LastWithT(predicateFn interface{}) interface{} {
|
||||||
|
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"LastWithT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.LastWith(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
// Max returns the maximum value in a collection of values.
|
// Max returns the maximum value in a collection of values.
|
||||||
func (q Query) Max() (r interface{}) {
|
func (q Query) Max() (r interface{}) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
@@ -230,8 +410,8 @@ func (q Query) SequenceEqual(q2 Query) bool {
|
|||||||
return !ok2
|
return !ok2
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single returns the only element of a collection, and nil
|
// Single returns the only element of a collection, and nil if there is not
|
||||||
// if there is not exactly one element in the collection.
|
// exactly one element in the collection.
|
||||||
func (q Query) Single() interface{} {
|
func (q Query) Single() interface{} {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
item, ok := next()
|
item, ok := next()
|
||||||
@@ -247,8 +427,8 @@ func (q Query) Single() interface{} {
|
|||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
// SingleWith returns the only element of a collection that satisfies
|
// SingleWith returns the only element of a collection that satisfies a
|
||||||
// a specified condition, and nil if more than one such element exists.
|
// specified condition, and nil if more than one such element exists.
|
||||||
func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) {
|
func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
found := false
|
found := false
|
||||||
@@ -267,10 +447,31 @@ func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SingleWithT is the typed version of SingleWith.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(TSource) bool"
|
||||||
|
//
|
||||||
|
// NOTE: SingleWith has better performance than SingleWithT.
|
||||||
|
func (q Query) SingleWithT(predicateFn interface{}) interface{} {
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"SingleWithT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.SingleWith(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
// SumInts computes the sum of a collection of numeric values.
|
// SumInts computes the sum of a collection of numeric values.
|
||||||
//
|
//
|
||||||
// Values can be of any integer type: int, int8, int16, int32, int64.
|
// Values can be of any integer type: int, int8, int16, int32, int64. The result
|
||||||
// The result is int64. Method returns zero if collection contains no elements.
|
// is int64. Method returns zero if collection contains no elements.
|
||||||
func (q Query) SumInts() (r int64) {
|
func (q Query) SumInts() (r int64) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
item, ok := next()
|
item, ok := next()
|
||||||
@@ -290,8 +491,9 @@ func (q Query) SumInts() (r int64) {
|
|||||||
|
|
||||||
// SumUInts computes the sum of a collection of numeric values.
|
// SumUInts computes the sum of a collection of numeric values.
|
||||||
//
|
//
|
||||||
// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, uint64.
|
// Values can be of any unsigned integer type: uint, uint8, uint16, uint32,
|
||||||
// The result is uint64. Method returns zero if collection contains no elements.
|
// uint64. The result is uint64. Method returns zero if collection contains no
|
||||||
|
// elements.
|
||||||
func (q Query) SumUInts() (r uint64) {
|
func (q Query) SumUInts() (r uint64) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
item, ok := next()
|
item, ok := next()
|
||||||
@@ -330,8 +532,8 @@ func (q Query) SumFloats() (r float64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToChannel iterates over a collection and outputs each element
|
// ToChannel iterates over a collection and outputs each element to a channel,
|
||||||
// to a channel, then closes it.
|
// then closes it.
|
||||||
func (q Query) ToChannel(result chan<- interface{}) {
|
func (q Query) ToChannel(result chan<- interface{}) {
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
|
|
||||||
@@ -343,8 +545,9 @@ func (q Query) ToChannel(result chan<- interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ToMap iterates over a collection and populates result map with elements.
|
// ToMap iterates over a collection and populates result map with elements.
|
||||||
// Collection elements have to be of KeyValue type to use this method.
|
// Collection elements have to be of KeyValue type to use this method. To
|
||||||
// To populate a map with elements of different type use ToMapBy method.
|
// populate a map with elements of different type use ToMapBy method. ToMap
|
||||||
|
// doesn't empty the result map before populating it.
|
||||||
func (q Query) ToMap(result interface{}) {
|
func (q Query) ToMap(result interface{}) {
|
||||||
q.ToMapBy(
|
q.ToMapBy(
|
||||||
result,
|
result,
|
||||||
@@ -356,15 +559,14 @@ func (q Query) ToMap(result interface{}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToMapBy iterates over a collection and populates result map with elements.
|
// ToMapBy iterates over a collection and populates the result map with
|
||||||
// Functions keySelector and valueSelector are executed for each element of the collection
|
// elements. Functions keySelector and valueSelector are executed for each
|
||||||
// to generate key and value for the map. Generated key and value types must be assignable
|
// element of the collection to generate key and value for the map. Generated
|
||||||
// to the map's key and value types.
|
// key and value types must be assignable to the map's key and value types.
|
||||||
func (q Query) ToMapBy(
|
// ToMapBy doesn't empty the result map before populating it.
|
||||||
result interface{},
|
func (q Query) ToMapBy(result interface{},
|
||||||
keySelector func(interface{}) interface{},
|
keySelector func(interface{}) interface{},
|
||||||
valueSelector func(interface{}) interface{},
|
valueSelector func(interface{}) interface{}) {
|
||||||
) {
|
|
||||||
res := reflect.ValueOf(result)
|
res := reflect.ValueOf(result)
|
||||||
m := reflect.Indirect(res)
|
m := reflect.Indirect(res)
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
@@ -379,16 +581,78 @@ func (q Query) ToMapBy(
|
|||||||
res.Elem().Set(m)
|
res.Elem().Set(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToSlice iterates over a collection and populates result slice with elements.
|
// ToMapByT is the typed version of ToMapBy.
|
||||||
// Collection elements must be assignable to the slice's element type.
|
//
|
||||||
func (q Query) ToSlice(result interface{}) {
|
// - keySelectorFn is of type "func(TSource)TKey"
|
||||||
res := reflect.ValueOf(result)
|
// - valueSelectorFn is of type "func(TSource)TValue"
|
||||||
|
//
|
||||||
|
// NOTE: ToMapBy has better performance than ToMapByT.
|
||||||
|
func (q Query) ToMapByT(result interface{},
|
||||||
|
keySelectorFn interface{}, valueSelectorFn interface{}) {
|
||||||
|
keySelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"ToMapByT", "keySelectorFn", keySelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
keySelectorFunc := func(item interface{}) interface{} {
|
||||||
|
return keySelectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
valueSelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"ToMapByT", "valueSelectorFn", valueSelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
valueSelectorFunc := func(item interface{}) interface{} {
|
||||||
|
return valueSelectorGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
q.ToMapBy(result, keySelectorFunc, valueSelectorFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToSlice iterates over a collection and saves the results in the slice pointed
|
||||||
|
// by v. It overwrites the existing slice, starting from index 0.
|
||||||
|
//
|
||||||
|
// If the slice pointed by v has sufficient capacity, v will be pointed to a
|
||||||
|
// resliced slice. If it does not, a new underlying array will be allocated and
|
||||||
|
// v will point to it.
|
||||||
|
func (q Query) ToSlice(v interface{}) {
|
||||||
|
res := reflect.ValueOf(v)
|
||||||
slice := reflect.Indirect(res)
|
slice := reflect.Indirect(res)
|
||||||
|
|
||||||
|
cap := slice.Cap()
|
||||||
|
res.Elem().Set(slice.Slice(0, cap)) // make len(slice)==cap(slice) from now on
|
||||||
|
|
||||||
next := q.Iterate()
|
next := q.Iterate()
|
||||||
|
index := 0
|
||||||
for item, ok := next(); ok; item, ok = next() {
|
for item, ok := next(); ok; item, ok = next() {
|
||||||
slice = reflect.Append(slice, reflect.ValueOf(item))
|
if index >= cap {
|
||||||
|
slice, cap = grow(slice)
|
||||||
|
}
|
||||||
|
slice.Index(index).Set(reflect.ValueOf(item))
|
||||||
|
index++
|
||||||
}
|
}
|
||||||
|
|
||||||
res.Elem().Set(slice)
|
// reslice the len(res)==cap(res) actual res size
|
||||||
|
res.Elem().Set(slice.Slice(0, index))
|
||||||
|
}
|
||||||
|
|
||||||
|
// grow grows the slice s by doubling its capacity, then it returns the new
|
||||||
|
// slice (resliced to its full capacity) and the new capacity.
|
||||||
|
func grow(s reflect.Value) (v reflect.Value, newCap int) {
|
||||||
|
cap := s.Cap()
|
||||||
|
if cap == 0 {
|
||||||
|
cap = 1
|
||||||
|
} else {
|
||||||
|
cap *= 2
|
||||||
|
}
|
||||||
|
newSlice := reflect.MakeSlice(s.Type(), cap, cap)
|
||||||
|
reflect.Copy(newSlice, s)
|
||||||
|
return newSlice, cap
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -2,9 +2,9 @@ package linq
|
|||||||
|
|
||||||
// Reverse inverts the order of the elements in a collection.
|
// Reverse inverts the order of the elements in a collection.
|
||||||
//
|
//
|
||||||
// Unlike OrderBy, this sorting method does not consider the actual values themselves
|
// Unlike OrderBy, this sorting method does not consider the actual values
|
||||||
// in determining the order. Rather, it just returns the elements in the reverse order
|
// themselves in determining the order. Rather, it just returns the elements in
|
||||||
// from which they are produced by the underlying source.
|
// the reverse order from which they are produced by the underlying source.
|
||||||
func (q Query) Reverse() Query {
|
func (q Query) Reverse() Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
|
|||||||
+65
-27
@@ -1,17 +1,16 @@
|
|||||||
package linq
|
package linq
|
||||||
|
|
||||||
// Select projects each element of a collection into a new form.
|
// Select projects each element of a collection into a new form. Returns a query
|
||||||
// Returns a query with the result of invoking the transform function
|
// with the result of invoking the transform function on each element of
|
||||||
// on each element of original source.
|
// original source.
|
||||||
//
|
//
|
||||||
// This projection method requires the transform function, selector,
|
// This projection method requires the transform function, selector, to produce
|
||||||
// to produce one value for each value in the source collection.
|
// one value for each value in the source collection. If selector returns a
|
||||||
// If selector returns a value that is itself a collection,
|
// value that is itself a collection, it is up to the consumer to traverse the
|
||||||
// it is up to the consumer to traverse the subcollections manually.
|
// subcollections manually. In such a situation, it might be better for your
|
||||||
// In such a situation, it might be better for your query to return a single
|
// query to return a single coalesced collection of values. To achieve this, use
|
||||||
// coalesced collection of values. To achieve this, use the SelectMany method
|
// the SelectMany method instead of Select. Although SelectMany works similarly
|
||||||
// instead of Select. Although SelectMany works similarly to Select,
|
// to Select, it differs in that the transform function returns a collection
|
||||||
// it differs in that the transform function returns a collection
|
|
||||||
// that is then expanded by SelectMany before it is returned.
|
// that is then expanded by SelectMany before it is returned.
|
||||||
func (q Query) Select(selector func(interface{}) interface{}) Query {
|
func (q Query) Select(selector func(interface{}) interface{}) Query {
|
||||||
return Query{
|
return Query{
|
||||||
@@ -31,24 +30,44 @@ func (q Query) Select(selector func(interface{}) interface{}) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectIndexed projects each element of a collection into a new form
|
// SelectT is the typed version of Select.
|
||||||
// by incorporating the element's index. Returns a query with the result
|
// - selectorFn is of type "func(TSource)TResult"
|
||||||
// of invoking the transform function on each element of original source.
|
// NOTE: Select has better performance than SelectT.
|
||||||
|
func (q Query) SelectT(selectorFn interface{}) Query {
|
||||||
|
|
||||||
|
selectGenericFunc, err := newGenericFunc(
|
||||||
|
"SelectT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(item interface{}) interface{} {
|
||||||
|
return selectGenericFunc.Call(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.Select(selectorFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectIndexed projects each element of a collection into a new form by
|
||||||
|
// incorporating the element's index. Returns a query with the result of
|
||||||
|
// invoking the transform function on each element of original source.
|
||||||
//
|
//
|
||||||
// The first argument to selector represents the zero-based index of that element
|
// The first argument to selector represents the zero-based index of that
|
||||||
// in the source collection. This can be useful if the elements are in a known order
|
// element in the source collection. This can be useful if the elements are in a
|
||||||
// and you want to do something with an element at a particular index,
|
// known order and you want to do something with an element at a particular
|
||||||
// for example. It can also be useful if you want to retrieve the index of one
|
// index, for example. It can also be useful if you want to retrieve the index
|
||||||
// or more elements. The second argument to selector represents the element to process.
|
// of one or more elements. The second argument to selector represents the
|
||||||
|
// element to process.
|
||||||
//
|
//
|
||||||
// This projection method requires the transform function, selector,
|
// This projection method requires the transform function, selector, to produce
|
||||||
// to produce one value for each value in the source collection.
|
// one value for each value in the source collection. If selector returns a
|
||||||
// If selector returns a value that is itself a collection,
|
// value that is itself a collection, it is up to the consumer to traverse the
|
||||||
// it is up to the consumer to traverse the subcollections manually.
|
// subcollections manually. In such a situation, it might be better for your
|
||||||
// In such a situation, it might be better for your query to return a single
|
// query to return a single coalesced collection of values. To achieve this, use
|
||||||
// coalesced collection of values. To achieve this, use the SelectMany method
|
// the SelectMany method instead of Select. Although SelectMany works similarly
|
||||||
// instead of Select. Although SelectMany works similarly to Select,
|
// to Select, it differs in that the transform function returns a collection
|
||||||
// it differs in that the transform function returns a collection
|
|
||||||
// that is then expanded by SelectMany before it is returned.
|
// that is then expanded by SelectMany before it is returned.
|
||||||
func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query {
|
func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query {
|
||||||
return Query{
|
return Query{
|
||||||
@@ -69,3 +88,22 @@ func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectIndexedT is the typed version of SelectIndexed.
|
||||||
|
// - selectorFn is of type "func(int,TSource)TResult"
|
||||||
|
// NOTE: SelectIndexed has better performance than SelectIndexedT.
|
||||||
|
func (q Query) SelectIndexedT(selectorFn interface{}) Query {
|
||||||
|
selectGenericFunc, err := newGenericFunc(
|
||||||
|
"SelectIndexedT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(index int, item interface{}) interface{} {
|
||||||
|
return selectGenericFunc.Call(index, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.SelectIndexed(selectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+134
-20
@@ -32,14 +32,37 @@ func (q Query) SelectMany(selector func(interface{}) Query) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectManyIndexed projects each element of a collection to a Query, iterates and
|
// SelectManyT is the typed version of SelectMany.
|
||||||
// flattens the resulting collection into one collection.
|
|
||||||
//
|
//
|
||||||
// The first argument to selector represents the zero-based index of that element
|
// - selectorFn is of type "func(TSource)Query"
|
||||||
// in the source collection. This can be useful if the elements are in a known order
|
//
|
||||||
// and you want to do something with an element at a particular index, for example.
|
// NOTE: SelectMany has better performance than SelectManyT.
|
||||||
// It can also be useful if you want to retrieve the index of one or more elements.
|
func (q Query) SelectManyT(selectorFn interface{}) Query {
|
||||||
// The second argument to selector represents the element to process.
|
|
||||||
|
selectManyGenericFunc, err := newGenericFunc(
|
||||||
|
"SelectManyT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(Query))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(inner interface{}) Query {
|
||||||
|
return selectManyGenericFunc.Call(inner).(Query)
|
||||||
|
}
|
||||||
|
return q.SelectMany(selectorFunc)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectManyIndexed projects each element of a collection to a Query, iterates
|
||||||
|
// and flattens the resulting collection into one collection.
|
||||||
|
//
|
||||||
|
// The first argument to selector represents the zero-based index of that
|
||||||
|
// element in the source collection. This can be useful if the elements are in a
|
||||||
|
// known order and you want to do something with an element at a particular
|
||||||
|
// index, for example. It can also be useful if you want to retrieve the index
|
||||||
|
// of one or more elements. The second argument to selector represents the
|
||||||
|
// element to process.
|
||||||
func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query {
|
func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -72,13 +95,33 @@ func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectManyIndexedT is the typed version of SelectManyIndexed.
|
||||||
|
//
|
||||||
|
// - selectorFn is of type "func(int,TSource)Query"
|
||||||
|
//
|
||||||
|
// NOTE: SelectManyIndexed has better performance than SelectManyIndexedT.
|
||||||
|
func (q Query) SelectManyIndexedT(selectorFn interface{}) Query {
|
||||||
|
|
||||||
|
selectManyIndexedGenericFunc, err := newGenericFunc(
|
||||||
|
"SelectManyIndexedT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(Query))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(index int, inner interface{}) Query {
|
||||||
|
return selectManyIndexedGenericFunc.Call(index, inner).(Query)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.SelectManyIndexed(selectorFunc)
|
||||||
|
}
|
||||||
|
|
||||||
// SelectManyBy projects each element of a collection to a Query, iterates and
|
// SelectManyBy projects each element of a collection to a Query, iterates and
|
||||||
// flattens the resulting collection into one collection, and invokes
|
// flattens the resulting collection into one collection, and invokes a result
|
||||||
// a result selector function on each element therein.
|
// selector function on each element therein.
|
||||||
func (q Query) SelectManyBy(
|
func (q Query) SelectManyBy(selector func(interface{}) Query,
|
||||||
selector func(interface{}) Query,
|
resultSelector func(interface{}, interface{}) interface{}) Query {
|
||||||
resultSelector func(interface{}, interface{}) interface{},
|
|
||||||
) Query {
|
|
||||||
|
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -103,18 +146,53 @@ func (q Query) SelectManyBy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item = resultSelector(outer, item)
|
item = resultSelector(item, outer)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SelectManyByIndexed projects each element of a collection to a Query, iterates and
|
// SelectManyByT is the typed version of SelectManyBy.
|
||||||
// flattens the resulting collection into one collection, and invokes
|
//
|
||||||
// a result selector function on each element therein.
|
// - selectorFn is of type "func(TSource)Query"
|
||||||
// The index of each source element is used in the intermediate projected form
|
// - resultSelectorFn is of type "func(TSource,TCollection)TResult"
|
||||||
// of that element.
|
//
|
||||||
|
// NOTE: SelectManyBy has better performance than SelectManyByT.
|
||||||
|
func (q Query) SelectManyByT(selectorFn interface{},
|
||||||
|
resultSelectorFn interface{}) Query {
|
||||||
|
|
||||||
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"SelectManyByT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(Query))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(outer interface{}) Query {
|
||||||
|
return selectorGenericFunc.Call(outer).(Query)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"SelectManyByT", "resultSelectorFn", resultSelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorFunc := func(outer interface{}, item interface{}) interface{} {
|
||||||
|
return resultSelectorGenericFunc.Call(outer, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.SelectManyBy(selectorFunc, resultSelectorFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectManyByIndexed projects each element of a collection to a Query,
|
||||||
|
// iterates and flattens the resulting collection into one collection, and
|
||||||
|
// invokes a result selector function on each element therein. The index of each
|
||||||
|
// source element is used in the intermediate projected form of that element.
|
||||||
func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query,
|
func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query,
|
||||||
resultSelector func(interface{}, interface{}) interface{}) Query {
|
resultSelector func(interface{}, interface{}) interface{}) Query {
|
||||||
|
|
||||||
@@ -143,9 +221,45 @@ func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item = resultSelector(outer, item)
|
item = resultSelector(item, outer)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SelectManyByIndexedT is the typed version of SelectManyByIndexed.
|
||||||
|
//
|
||||||
|
// - selectorFn is of type "func(int,TSource)Query"
|
||||||
|
// - resultSelectorFn is of type "func(TSource,TCollection)TResult"
|
||||||
|
//
|
||||||
|
// NOTE: SelectManyByIndexed has better performance than
|
||||||
|
// SelectManyByIndexedT.
|
||||||
|
func (q Query) SelectManyByIndexedT(selectorFn interface{},
|
||||||
|
resultSelectorFn interface{}) Query {
|
||||||
|
selectorGenericFunc, err := newGenericFunc(
|
||||||
|
"SelectManyByIndexedT", "selectorFn", selectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(Query))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
selectorFunc := func(index int, outer interface{}) Query {
|
||||||
|
return selectorGenericFunc.Call(index, outer).(Query)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"SelectManyByIndexedT", "resultSelectorFn", resultSelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorFunc := func(outer interface{}, item interface{}) interface{} {
|
||||||
|
return resultSelectorGenericFunc.Call(outer, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.SelectManyByIndexed(selectorFunc, resultSelectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
+58
-15
@@ -1,7 +1,7 @@
|
|||||||
package linq
|
package linq
|
||||||
|
|
||||||
// Skip bypasses a specified number of elements in a collection
|
// Skip bypasses a specified number of elements in a collection and then returns
|
||||||
// and then returns the remaining elements.
|
// the remaining elements.
|
||||||
func (q Query) Skip(count int) Query {
|
func (q Query) Skip(count int) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -22,13 +22,13 @@ func (q Query) Skip(count int) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SkipWhile bypasses elements in a collection as long as a specified condition is true
|
// SkipWhile bypasses elements in a collection as long as a specified condition
|
||||||
// and then returns the remaining elements.
|
// is true and then returns the remaining elements.
|
||||||
//
|
//
|
||||||
// This method tests each element by using predicate and skips the element
|
// This method tests each element by using predicate and skips the element if
|
||||||
// if the result is true. After the predicate function returns false for an element,
|
// the result is true. After the predicate function returns false for an
|
||||||
// that element and the remaining elements in source are returned
|
// element, that element and the remaining elements in source are returned and
|
||||||
// and there are no more invocations of predicate.
|
// there are no more invocations of predicate.
|
||||||
func (q Query) SkipWhile(predicate func(interface{}) bool) Query {
|
func (q Query) SkipWhile(predicate func(interface{}) bool) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -54,14 +54,36 @@ func (q Query) SkipWhile(predicate func(interface{}) bool) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SkipWhileIndexed bypasses elements in a collection as long as a specified condition
|
// SkipWhileT is the typed version of SkipWhile.
|
||||||
// is true and then returns the remaining elements. The element's index is used
|
|
||||||
// in the logic of the predicate function.
|
|
||||||
//
|
//
|
||||||
// This method tests each element by using predicate and skips the element
|
// - predicateFn is of type "func(TSource)bool"
|
||||||
// if the result is true. After the predicate function returns false for an element,
|
//
|
||||||
// that element and the remaining elements in source are returned
|
// NOTE: SkipWhile has better performance than SkipWhileT.
|
||||||
// and there are no more invocations of predicate.
|
func (q Query) SkipWhileT(predicateFn interface{}) Query {
|
||||||
|
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"SkipWhileT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.SkipWhile(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SkipWhileIndexed bypasses elements in a collection as long as a specified
|
||||||
|
// condition is true and then returns the remaining elements. The element's
|
||||||
|
// index is used in the logic of the predicate function.
|
||||||
|
//
|
||||||
|
// This method tests each element by using predicate and skips the element if
|
||||||
|
// the result is true. After the predicate function returns false for an
|
||||||
|
// element, that element and the remaining elements in source are returned and
|
||||||
|
// there are no more invocations of predicate.
|
||||||
func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query {
|
func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -89,3 +111,24 @@ func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SkipWhileIndexedT is the typed version of SkipWhileIndexed.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(int,TSource)bool"
|
||||||
|
//
|
||||||
|
// NOTE: SkipWhileIndexed has better performance than SkipWhileIndexedT.
|
||||||
|
func (q Query) SkipWhileIndexedT(predicateFn interface{}) Query {
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"SkipWhileIndexedT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(index int, item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(index, item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.SkipWhileIndexed(predicateFunc)
|
||||||
|
}
|
||||||
|
|||||||
+52
-7
@@ -1,6 +1,7 @@
|
|||||||
package linq
|
package linq
|
||||||
|
|
||||||
// Take returns a specified number of contiguous elements from the start of a collection.
|
// Take returns a specified number of contiguous elements from the start of a
|
||||||
|
// collection.
|
||||||
func (q Query) Take(count int) Query {
|
func (q Query) Take(count int) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -19,8 +20,8 @@ func (q Query) Take(count int) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TakeWhile returns elements from a collection as long as a specified condition is true,
|
// TakeWhile returns elements from a collection as long as a specified condition
|
||||||
// and then skips the remaining elements.
|
// is true, and then skips the remaining elements.
|
||||||
func (q Query) TakeWhile(predicate func(interface{}) bool) Query {
|
func (q Query) TakeWhile(predicate func(interface{}) bool) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -49,10 +50,33 @@ func (q Query) TakeWhile(predicate func(interface{}) bool) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TakeWhileIndexed returns elements from a collection as long as a specified condition
|
// TakeWhileT is the typed version of TakeWhile.
|
||||||
// is true. The element's index is used in the logic of the predicate function.
|
//
|
||||||
// The first argument of predicate represents the zero-based index of the element
|
// - predicateFn is of type "func(TSource)bool"
|
||||||
// within collection. The second argument represents the element to test.
|
//
|
||||||
|
// NOTE: TakeWhile has better performance than TakeWhileT.
|
||||||
|
func (q Query) TakeWhileT(predicateFn interface{}) Query {
|
||||||
|
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"TakeWhileT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.TakeWhile(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TakeWhileIndexed returns elements from a collection as long as a specified
|
||||||
|
// condition is true. The element's index is used in the logic of the predicate
|
||||||
|
// function. The first argument of predicate represents the zero-based index of
|
||||||
|
// the element within collection. The second argument represents the element to
|
||||||
|
// test.
|
||||||
func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query {
|
func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -82,3 +106,24 @@ func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TakeWhileIndexedT is the typed version of TakeWhileIndexed.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(int,TSource)bool"
|
||||||
|
//
|
||||||
|
// NOTE: TakeWhileIndexed has better performance than TakeWhileIndexedT.
|
||||||
|
func (q Query) TakeWhileIndexedT(predicateFn interface{}) Query {
|
||||||
|
whereFunc, err := newGenericFunc(
|
||||||
|
"TakeWhileIndexedT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(index int, item interface{}) bool {
|
||||||
|
return whereFunc.Call(index, item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.TakeWhileIndexed(predicateFunc)
|
||||||
|
}
|
||||||
|
|||||||
+3
-4
@@ -2,10 +2,9 @@ package linq
|
|||||||
|
|
||||||
// Union produces the set union of two collections.
|
// Union produces the set union of two collections.
|
||||||
//
|
//
|
||||||
// This method excludes duplicates from the return set.
|
// This method excludes duplicates from the return set. This is different
|
||||||
// This is different behavior to the Concat method,
|
// behavior to the Concat method, which returns all the elements in the input
|
||||||
// which returns all the elements in the input collection
|
// collection including duplicates.
|
||||||
// including duplicates.
|
|
||||||
func (q Query) Union(q2 Query) Query {
|
func (q Query) Union(q2 Query) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
|
|||||||
+47
-4
@@ -19,11 +19,33 @@ func (q Query) Where(predicate func(interface{}) bool) Query {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WhereIndexed filters a collection of values based on a predicate.
|
// WhereT is the typed version of Where.
|
||||||
// Each element's index is used in the logic of the predicate function.
|
|
||||||
//
|
//
|
||||||
// The first argument represents the zero-based index of the element within collection.
|
// - predicateFn is of type "func(TSource)bool"
|
||||||
// The second argument of predicate represents the element to test.
|
//
|
||||||
|
// NOTE: Where has better performance than WhereT.
|
||||||
|
func (q Query) WhereT(predicateFn interface{}) Query {
|
||||||
|
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"WhereT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.Where(predicateFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WhereIndexed filters a collection of values based on a predicate. Each
|
||||||
|
// element's index is used in the logic of the predicate function.
|
||||||
|
//
|
||||||
|
// The first argument represents the zero-based index of the element within
|
||||||
|
// collection. The second argument of predicate represents the element to test.
|
||||||
func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query {
|
func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query {
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -44,3 +66,24 @@ func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WhereIndexedT is the typed version of WhereIndexed.
|
||||||
|
//
|
||||||
|
// - predicateFn is of type "func(int,TSource)bool"
|
||||||
|
//
|
||||||
|
// NOTE: WhereIndexed has better performance than WhereIndexedT.
|
||||||
|
func (q Query) WhereIndexedT(predicateFn interface{}) Query {
|
||||||
|
predicateGenericFunc, err := newGenericFunc(
|
||||||
|
"WhereIndexedT", "predicateFn", predicateFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), newElemTypeSlice(new(bool))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
predicateFunc := func(index int, item interface{}) bool {
|
||||||
|
return predicateGenericFunc.Call(index, item).(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.WhereIndexed(predicateFunc)
|
||||||
|
}
|
||||||
|
|||||||
+32
-12
@@ -1,19 +1,17 @@
|
|||||||
package linq
|
package linq
|
||||||
|
|
||||||
// Zip applies a specified function to the corresponding elements
|
// Zip applies a specified function to the corresponding elements of two
|
||||||
// of two collections, producing a collection of the results.
|
// collections, producing a collection of the results.
|
||||||
//
|
//
|
||||||
// The method steps through the two input collections, applying function
|
// The method steps through the two input collections, applying function
|
||||||
// resultSelector to corresponding elements of the two collections.
|
// resultSelector to corresponding elements of the two collections. The method
|
||||||
// The method returns a collection of the values that are returned by resultSelector.
|
// returns a collection of the values that are returned by resultSelector. If
|
||||||
// If the input collections do not have the same number of elements,
|
// the input collections do not have the same number of elements, the method
|
||||||
// the method combines elements until it reaches the end of one of the collections.
|
// combines elements until it reaches the end of one of the collections. For
|
||||||
// For example, if one collection has three elements and the other one has four,
|
// example, if one collection has three elements and the other one has four, the
|
||||||
// the result collection has only three elements.
|
// result collection has only three elements.
|
||||||
func (q Query) Zip(
|
func (q Query) Zip(q2 Query,
|
||||||
q2 Query,
|
resultSelector func(interface{}, interface{}) interface{}) Query {
|
||||||
resultSelector func(interface{}, interface{}) interface{},
|
|
||||||
) Query {
|
|
||||||
|
|
||||||
return Query{
|
return Query{
|
||||||
Iterate: func() Iterator {
|
Iterate: func() Iterator {
|
||||||
@@ -33,3 +31,25 @@ func (q Query) Zip(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ZipT is the typed version of Zip.
|
||||||
|
//
|
||||||
|
// - resultSelectorFn is of type "func(TFirst,TSecond)TResult"
|
||||||
|
//
|
||||||
|
// NOTE: Zip has better performance than ZipT.
|
||||||
|
func (q Query) ZipT(q2 Query,
|
||||||
|
resultSelectorFn interface{}) Query {
|
||||||
|
resultSelectorGenericFunc, err := newGenericFunc(
|
||||||
|
"ZipT", "resultSelectorFn", resultSelectorFn,
|
||||||
|
simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resultSelectorFunc := func(item1 interface{}, item2 interface{}) interface{} {
|
||||||
|
return resultSelectorGenericFunc.Call(item1, item2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return q.Zip(q2, resultSelectorFunc)
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+3
-1
@@ -1,4 +1,4 @@
|
|||||||
# github.com/ahmetb/go-linq v2.0.0-rc0+incompatible
|
# github.com/ahmetb/go-linq v3.0.0+incompatible
|
||||||
github.com/ahmetb/go-linq
|
github.com/ahmetb/go-linq
|
||||||
# github.com/go-ini/ini v1.57.0
|
# github.com/go-ini/ini v1.57.0
|
||||||
github.com/go-ini/ini
|
github.com/go-ini/ini
|
||||||
@@ -8,3 +8,5 @@ github.com/json-iterator/go
|
|||||||
github.com/modern-go/concurrent
|
github.com/modern-go/concurrent
|
||||||
# github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742
|
# github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742
|
||||||
github.com/modern-go/reflect2
|
github.com/modern-go/reflect2
|
||||||
|
# gopkg.in/yaml.v2 v2.4.0
|
||||||
|
gopkg.in/yaml.v2
|
||||||
|
|||||||
Reference in New Issue
Block a user