1go-funk
2=======
3
4.. image:: https://secure.travis-ci.org/thoas/go-funk.svg?branch=master
5 :alt: Build Status
6 :target: http://travis-ci.org/thoas/go-funk
7
8.. image:: https://godoc.org/github.com/thoas/go-funk?status.svg
9 :alt: GoDoc
10 :target: https://godoc.org/github.com/thoas/go-funk
11
12.. image:: https://goreportcard.com/badge/github.com/thoas/go-funk
13 :alt: Go report
14 :target: https://goreportcard.com/report/github.com/thoas/go-funk
15
16``go-funk`` is a modern Go library based on reflect_.
17
18Generic helpers rely on reflect_, be careful this code runs exclusively on runtime so you must have a good test suite.
19
20These helpers have started as an experiment to learn reflect_. It may look like lodash_ in some aspects but
21it will have its own roadmap. lodash_ is an awesome library with a lot of work behind it, all features included in
22``go-funk`` come from internal use cases.
23
24You can also find typesafe implementation in the godoc_.
25
26Why this name?
27--------------
28
29Long story, short answer because ``func`` is a reserved word in Go, I wanted something similar.
30
31Initially this project was named ``fn`` I don't need to explain why that was a bad idea for french speakers :)
32
33Let's ``funk``!
34
35.. image:: https://media.giphy.com/media/3oEjHQKtDXpeGN9rW0/giphy.gif
36
37<3
38
39Installation
40------------
41
42.. code-block:: bash
43
44 go get github.com/thoas/go-funk
45
46Usage
47-----
48
49.. code-block:: go
50
51 import "github.com/thoas/go-funk"
52
53These examples will be based on the following data model:
54
55.. code-block:: go
56
57 type Foo struct {
58 ID int
59 FirstName string `tag_name:"tag 1"`
60 LastName string `tag_name:"tag 2"`
61 Age int `tag_name:"tag 3"`
62 }
63
64 func (f Foo) TableName() string {
65 return "foo"
66 }
67
68With fixtures:
69
70.. code-block:: go
71
72 f := &Foo{
73 ID: 1,
74 FirstName: "Foo",
75 LastName: "Bar",
76 Age: 30,
77 }
78
79You can import ``go-funk`` using a basic statement:
80
81.. code-block:: go
82
83 import "github.com/thoas/go-funk"
84
85funk.Contains
86.............
87
88Returns true if an element is present in a iteratee (slice, map, string).
89
90One frustrating thing in Go is to implement ``contains`` methods for each type, for example:
91
92.. code-block:: go
93
94 func ContainsInt(s []int, e int) bool {
95 for _, a := range s {
96 if a == e {
97 return true
98 }
99 }
100 return false
101 }
102
103this can be replaced by ``funk.Contains``:
104
105.. code-block:: go
106
107 // slice of string
108 funk.Contains([]string{"foo", "bar"}, "bar") // true
109
110 // slice of Foo ptr
111 funk.Contains([]*Foo{f}, f) // true
112 funk.Contains([]*Foo{f}, nil) // false
113
114 b := &Foo{
115 ID: 2,
116 FirstName: "Florent",
117 LastName: "Messa",
118 Age: 28,
119 }
120
121 funk.Contains([]*Foo{f}, b) // false
122
123 // string
124 funk.Contains("florent", "rent") // true
125 funk.Contains("florent", "foo") // false
126
127 // even map
128 funk.Contains(map[int]string{1: "Florent"}, 1) // true
129
130see also, typesafe implementations: ContainsInt_, ContainsInt64_, ContainsFloat32_, ContainsFloat64_, ContainsString_
131
132.. _ContainsFloat32: https://godoc.org/github.com/thoas/go-funk#ContainsFloat32
133.. _ContainsFloat64: https://godoc.org/github.com/thoas/go-funk#ContainsFloat64
134.. _ContainsInt: https://godoc.org/github.com/thoas/go-funk#ContainsInt
135.. _ContainsInt64: https://godoc.org/github.com/thoas/go-funk#ContainsInt64
136.. _ContainsString: https://godoc.org/github.com/thoas/go-funk#ContainsString
137
138funk.Intersect
139..............
140
141Returns the intersection between two collections.
142
143.. code-block:: go
144
145 funk.Intersect([]int{1, 2, 3, 4}, []int{2, 4, 6}) // []int{2, 4}
146 funk.Intersect([]string{"foo", "bar", "hello", "bar"}, []string{"foo", "bar"}) // []string{"foo", "bar"}
147
148see also, typesafe implementations: IntersectString
149
150.. IntersectString: https://godoc.org/github.com/thoas/go-funk#IntersectString
151
152
153funk.Difference
154..............
155
156Returns the difference between two collections.
157
158.. code-block:: go
159
160 funk.Difference([]int{1, 2, 3, 4}, []int{2, 4, 6}) // []int{1, 3}, []int{6}
161 funk.Difference([]string{"foo", "bar", "hello", "bar"}, []string{"foo", "bar"}) // []string{"hello"}, []string{}
162
163see also, typesafe implementations: DifferenceString
164
165.. DifferenceString: https://godoc.org/github.com/thoas/go-funk#DifferenceString
166
167
168funk.IndexOf
169............
170
171Gets the index at which the first occurrence of a value is found in an array or return -1
172if the value cannot be found.
173
174.. code-block:: go
175
176 // slice of string
177 funk.IndexOf([]string{"foo", "bar"}, "bar") // 1
178 funk.IndexOf([]string{"foo", "bar"}, "gilles") // -1
179
180see also, typesafe implementations: IndexOfInt_, IndexOfInt64_, IndexOfFloat32_, IndexOfFloat64_, IndexOfString_
181
182.. _IndexOfFloat32: https://godoc.org/github.com/thoas/go-funk#IndexOfFloat32
183.. _IndexOfFloat64: https://godoc.org/github.com/thoas/go-funk#IndexOfFloat64
184.. _IndexOfInt: https://godoc.org/github.com/thoas/go-funk#IndexOfInt
185.. _IndexOfInt64: https://godoc.org/github.com/thoas/go-funk#IndexOfInt64
186.. _IndexOfString: https://godoc.org/github.com/thoas/go-funk#IndexOfString
187
188funk.LastIndexOf
189................
190
191Gets the index at which the last occurrence of a value is found in an array or return -1
192if the value cannot be found.
193
194.. code-block:: go
195
196 // slice of string
197 funk.LastIndexOf([]string{"foo", "bar", "bar"}, "bar") // 2
198 funk.LastIndexOf([]string{"foo", "bar"}, "gilles") // -1
199
200see also, typesafe implementations: LastIndexOfInt_, LastIndexOfInt64_, LastIndexOfFloat32_, LastIndexOfFloat64_, LastIndexOfString_
201
202.. _LastIndexOfFloat32: https://godoc.org/github.com/thoas/go-funk#LastIndexOfFloat32
203.. _LastIndexOfFloat64: https://godoc.org/github.com/thoas/go-funk#LastIndexOfFloat64
204.. _LastIndexOfInt: https://godoc.org/github.com/thoas/go-funk#LastIndexOfInt
205.. _LastIndexOfInt64: https://godoc.org/github.com/thoas/go-funk#LastIndexOfInt64
206.. _LastIndexOfString: https://godoc.org/github.com/thoas/go-funk#LastIndexOfString
207
208funk.ToMap
209..........
210
211Transforms a slice of structs to a map based on a ``pivot`` field.
212
213.. code-block:: go
214
215 f := &Foo{
216 ID: 1,
217 FirstName: "Gilles",
218 LastName: "Fabio",
219 Age: 70,
220 }
221
222 b := &Foo{
223 ID: 2,
224 FirstName: "Florent",
225 LastName: "Messa",
226 Age: 80,
227 }
228
229 results := []*Foo{f, b}
230
231 mapping := funk.ToMap(results, "ID") // map[int]*Foo{1: f, 2: b}
232
233funk.Filter
234...........
235
236Filters a slice based on a predicate.
237
238.. code-block:: go
239
240 r := funk.Filter([]int{1, 2, 3, 4}, func(x int) bool {
241 return x%2 == 0
242 }) // []int{2, 4}
243
244see also, typesafe implementations: FilterInt_, FilterInt64_, FilterFloat32_, FilterFloat64_, FilterString_
245
246.. _FilterFloat32: https://godoc.org/github.com/thoas/go-funk#FilterFloat32
247.. _FilterFloat64: https://godoc.org/github.com/thoas/go-funk#FilterFloat64
248.. _FilterInt: https://godoc.org/github.com/thoas/go-funk#FilterInt
249.. _FilterInt64: https://godoc.org/github.com/thoas/go-funk#FilterInt64
250.. _FilterString: https://godoc.org/github.com/thoas/go-funk#FilterString
251
252funk.Find
253.........
254
255Finds an element in a slice based on a predicate.
256
257.. code-block:: go
258
259 r := funk.Find([]int{1, 2, 3, 4}, func(x int) bool {
260 return x%2 == 0
261 }) // 2
262
263see also, typesafe implementations: FindInt_, FindInt64_, FindFloat32_, FindFloat64_, FindString_
264
265.. _FindFloat32: https://godoc.org/github.com/thoas/go-funk#FindFloat32
266.. _FindFloat64: https://godoc.org/github.com/thoas/go-funk#FindFloat64
267.. _FindInt: https://godoc.org/github.com/thoas/go-funk#FindInt
268.. _FindInt64: https://godoc.org/github.com/thoas/go-funk#FindInt64
269.. _FindString: https://godoc.org/github.com/thoas/go-funk#FindString
270
271funk.Map
272........
273
274Manipulates an iteratee (map, slice) and transforms it to another type:
275
276* map -> slice
277* map -> map
278* slice -> map
279* slice -> slice
280
281.. code-block:: go
282
283 r := funk.Map([]int{1, 2, 3, 4}, func(x int) int {
284 return x * 2
285 }) // []int{2, 4, 6, 8}
286
287 r := funk.Map([]int{1, 2, 3, 4}, func(x int) string {
288 return "Hello"
289 }) // []string{"Hello", "Hello", "Hello", "Hello"}
290
291 r = funk.Map([]int{1, 2, 3, 4}, func(x int) (int, int) {
292 return x, x
293 }) // map[int]int{1: 1, 2: 2, 3: 3, 4: 4}
294
295 mapping := map[int]string{
296 1: "Florent",
297 2: "Gilles",
298 }
299
300 r = funk.Map(mapping, func(k int, v string) int {
301 return k
302 }) // []int{1, 2}
303
304 r = funk.Map(mapping, func(k int, v string) (string, string) {
305 return fmt.Sprintf("%d", k), v
306 }) // map[string]string{"1": "Florent", "2": "Gilles"}
307
308funk.Get
309........
310
311Retrieves the value at path of struct(s).
312
313.. code-block:: go
314
315 var bar *Bar = &Bar{
316 Name: "Test",
317 Bars: []*Bar{
318 &Bar{
319 Name: "Level1-1",
320 Bar: &Bar{
321 Name: "Level2-1",
322 },
323 },
324 &Bar{
325 Name: "Level1-2",
326 Bar: &Bar{
327 Name: "Level2-2",
328 },
329 },
330 },
331 }
332
333 var foo *Foo = &Foo{
334 ID: 1,
335 FirstName: "Dark",
336 LastName: "Vador",
337 Age: 30,
338 Bar: bar,
339 Bars: []*Bar{
340 bar,
341 bar,
342 },
343 }
344
345 funk.Get([]*Foo{foo}, "Bar.Bars.Bar.Name") // []string{"Level2-1", "Level2-2"}
346 funk.Get(foo, "Bar.Bars.Bar.Name") // []string{"Level2-1", "Level2-2"}
347 funk.Get(foo, "Bar.Name") // Test
348
349``funk.Get`` also handles ``nil`` values:
350
351.. code-block:: go
352
353 bar := &Bar{
354 Name: "Test",
355 }
356
357 foo1 := &Foo{
358 ID: 1,
359 FirstName: "Dark",
360 LastName: "Vador",
361 Age: 30,
362 Bar: bar,
363 }
364
365 foo2 := &Foo{
366 ID: 1,
367 FirstName: "Dark",
368 LastName: "Vador",
369 Age: 30,
370 } // foo2.Bar is nil
371
372 funk.Get([]*Foo{foo1, foo2}, "Bar.Name") // []string{"Test"}
373 funk.Get(foo2, "Bar.Name") // nil
374
375
376
377funk.GetOrElse
378..............
379
380Retrieves the value of the pointer or default.
381
382.. code-block:: go
383
384 str := "hello world"
385 GetOrElse(&str, "foobar") // string{"hello world"}
386 GetOrElse(str, "foobar") // string{"hello world"}
387 GetOrElse(nil, "foobar") // string{"foobar"}
388
389
390funk.Keys
391.........
392
393Creates an array of the own enumerable map keys or struct field names.
394
395.. code-block:: go
396
397 funk.Keys(map[string]int{"one": 1, "two": 2}) // []string{"one", "two"} (iteration order is not guaranteed)
398
399 foo := &Foo{
400 ID: 1,
401 FirstName: "Dark",
402 LastName: "Vador",
403 Age: 30,
404 }
405
406 funk.Keys(foo) // []string{"ID", "FirstName", "LastName", "Age"} (iteration order is not guaranteed)
407
408funk.Values
409...........
410
411Creates an array of the own enumerable map values or struct field values.
412
413.. code-block:: go
414
415 funk.Values(map[string]int{"one": 1, "two": 2}) // []string{1, 2} (iteration order is not guaranteed)
416
417 foo := &Foo{
418 ID: 1,
419 FirstName: "Dark",
420 LastName: "Vador",
421 Age: 30,
422 }
423
424 funk.Values(foo) // []interface{}{1, "Dark", "Vador", 30} (iteration order is not guaranteed)
425
426funk.ForEach
427............
428
429Range over an iteratee (map, slice).
430
431.. code-block:: go
432
433 funk.ForEach([]int{1, 2, 3, 4}, func(x int) {
434 fmt.Println(x)
435 })
436
437funk.ForEachRight
438............
439
440Range over an iteratee (map, slice) from the right.
441
442.. code-block:: go
443
444 results := []int{}
445
446 funk.ForEachRight([]int{1, 2, 3, 4}, func(x int) {
447 results = append(results, x)
448 })
449
450 fmt.Println(results) // []int{4, 3, 2, 1}
451
452funk.Chunk
453..........
454
455Creates an array of elements split into groups with the length of the size.
456If array can't be split evenly, the final chunk will be the remaining element.
457
458.. code-block:: go
459
460 funk.Chunk([]int{1, 2, 3, 4, 5}, 2) // [][]int{[]int{1, 2}, []int{3, 4}, []int{5}}
461
462funk.FlattenDeep
463................
464
465Recursively flattens an array.
466
467.. code-block:: go
468
469 funk.FlattenDeep([][]int{[]int{1, 2}, []int{3, 4}}) // []int{1, 2, 3, 4}
470
471funk.Uniq
472.........
473
474Creates an array with unique values.
475
476.. code-block:: go
477
478 funk.Uniq([]int{0, 1, 1, 2, 3, 0, 0, 12}) // []int{0, 1, 2, 3, 12}
479
480see also, typesafe implementations: UniqInt_, UniqInt64_, UniqFloat32_, UniqFloat64_, UniqString_
481
482.. _UniqFloat32: https://godoc.org/github.com/thoas/go-funk#UniqFloat32
483.. _UniqFloat64: https://godoc.org/github.com/thoas/go-funk#UniqFloat64
484.. _UniqInt: https://godoc.org/github.com/thoas/go-funk#UniqInt
485.. _UniqInt64: https://godoc.org/github.com/thoas/go-funk#UniqInt64
486.. _UniqString: https://godoc.org/github.com/thoas/go-funk#UniqString
487
488funk.Drop
489.........
490
491Creates an array/slice with `n` elements dropped from the beginning.
492
493.. code-block:: go
494
495 funk.Drop([]int{0, 0, 0, 0}, 3) // []int{0}
496
497see also, typesafe implementations: DropInt_, DropInt32_, DropInt64_, DropFloat32_, DropFloat64_, DropString_
498
499.. _DropInt: https://godoc.org/github.com/thoas/go-funk#DropInt
500.. _DropInt32: https://godoc.org/github.com/thoas/go-funk#DropInt64
501.. _DropInt64: https://godoc.org/github.com/thoas/go-funk#DropInt64
502.. _DropFloat32: https://godoc.org/github.com/thoas/go-funk#DropFloat32
503.. _DropFloat64: https://godoc.org/github.com/thoas/go-funk#DropFloat64
504.. _DropString: https://godoc.org/github.com/thoas/go-funk#DropString
505
506funk.Initial
507............
508
509Gets all but the last element of array.
510
511.. code-block:: go
512
513 funk.Initial([]int{0, 1, 2, 3, 4}) // []int{0, 1, 2, 3}
514
515funk.Tail
516.........
517
518Gets all but the first element of array.
519
520.. code-block:: go
521
522 funk.Tail([]int{0, 1, 2, 3, 4}) // []int{1, 2, 3, 4}
523
524funk.Shuffle
525............
526
527Creates an array of shuffled values.
528
529.. code-block:: go
530
531 funk.Shuffle([]int{0, 1, 2, 3, 4}) // []int{2, 1, 3, 4, 0}
532
533
534see also, typesafe implementations: ShuffleInt_, ShuffleInt64_, ShuffleFloat32_, ShuffleFloat64_, ShuffleString_
535
536.. _ShuffleFloat32: https://godoc.org/github.com/thoas/go-funk#ShuffleFloat32
537.. _ShuffleFloat64: https://godoc.org/github.com/thoas/go-funk#ShuffleFloat64
538.. _ShuffleInt: https://godoc.org/github.com/thoas/go-funk#ShuffleInt
539.. _ShuffleInt64: https://godoc.org/github.com/thoas/go-funk#ShuffleInt64
540.. _ShuffleString: https://godoc.org/github.com/thoas/go-funk#ShuffleString
541
542funk.Subtract
543.............
544
545Returns the subtraction between two collections. It preserve order.
546
547.. code-block:: go
548
549 funk.Subtract([]int{0, 1, 2, 3, 4}, []int{0, 4}) // []int{1, 2, 3}
550 funk.Subtract([]int{0, 3, 2, 3, 4}, []int{0, 4}) // []int{3, 2, 3}
551
552
553see also, typesafe implementations: SubtractString_
554
555.. SubtractString: https://godoc.org/github.com/thoas/go-funk#SubtractString
556
557funk.Sum
558........
559
560Computes the sum of the values in an array.
561
562.. code-block:: go
563
564 funk.Sum([]int{0, 1, 2, 3, 4}) // 10.0
565 funk.Sum([]interface{}{0.5, 1, 2, 3, 4}) // 10.5
566
567see also, typesafe implementations: SumInt_, SumInt64_, SumFloat32_, SumFloat64_
568
569.. _SumFloat32: https://godoc.org/github.com/thoas/go-funk#SumFloat32
570.. _SumFloat64: https://godoc.org/github.com/thoas/go-funk#SumFloat64
571.. _SumInt: https://godoc.org/github.com/thoas/go-funk#SumInt
572.. _SumInt64: https://godoc.org/github.com/thoas/go-funk#SumInt64
573
574funk.Reverse
575............
576
577Transforms an array such that the first element will become the last, the second element
578will become the second to last, etc.
579
580.. code-block:: go
581
582 funk.Reverse([]int{0, 1, 2, 3, 4}) // []int{4, 3, 2, 1, 0}
583
584see also, typesafe implementations: ReverseInt_, ReverseInt64_, ReverseFloat32_, ReverseFloat64_, ReverseString_, ReverseStrings_
585
586.. _ReverseFloat32: https://godoc.org/github.com/thoas/go-funk#ReverseFloat32
587.. _ReverseFloat64: https://godoc.org/github.com/thoas/go-funk#ReverseFloat64
588.. _ReverseInt: https://godoc.org/github.com/thoas/go-funk#ReverseInt
589.. _ReverseInt64: https://godoc.org/github.com/thoas/go-funk#ReverseInt64
590.. _ReverseString: https://godoc.org/github.com/thoas/go-funk#ReverseString
591.. _ReverseStrings: https://godoc.org/github.com/thoas/go-funk#ReverseStrings
592
593funk.SliceOf
594............
595
596Returns a slice based on an element.
597
598.. code-block:: go
599
600 funk.SliceOf(f) // will return a []*Foo{f}
601
602funk.RandomInt
603..............
604
605Generates a random int, based on a min and max values.
606
607.. code-block:: go
608
609 funk.RandomInt(0, 100) // will be between 0 and 100
610
611funk.RandomString
612.................
613
614Generates a random string with a fixed length.
615
616.. code-block:: go
617
618 funk.RandomString(4) // will be a string of 4 random characters
619
620funk.Shard
621..........
622
623Generates a sharded string with a fixed length and depth.
624
625.. code-block:: go
626
627 funk.Shard("e89d66bdfdd4dd26b682cc77e23a86eb", 1, 2, false) // []string{"e", "8", "e89d66bdfdd4dd26b682cc77e23a86eb"}
628
629 funk.Shard("e89d66bdfdd4dd26b682cc77e23a86eb", 2, 2, false) // []string{"e8", "9d", "e89d66bdfdd4dd26b682cc77e23a86eb"}
630
631 funk.Shard("e89d66bdfdd4dd26b682cc77e23a86eb", 2, 2, true) // []string{"e8", "9d", "66", "bdfdd4dd26b682cc77e23a86eb"}
632
633funk.Subset
634.............
635
636Returns true if a collection is a subset of another
637
638.. code-block:: go
639
640 funk.Subset([]int{1, 2, 4}, []int{1, 2, 3, 4, 5}) // true
641 funk.Subset([]string{"foo", "bar"},[]string{"foo", "bar", "hello", "bar", "hi"}) //true
642
643
644Performance
645-----------
646
647``go-funk`` currently has an open issue about performance_, don't hesitate to participate in the discussion
648to enhance the generic helpers implementations.
649
650Let's stop beating around the bush, a typesafe implementation in pure Go of ``funk.Contains``, let's say for example:
651
652.. code-block:: go
653
654 func ContainsInt(s []int, e int) bool {
655 for _, a := range s {
656 if a == e {
657 return true
658 }
659 }
660 return false
661 }
662
663will always outperform an implementation based on reflect_ in terms of speed and allocs because of
664how it's implemented in the language.
665
666If you want a similarity, gorm_ will always be slower than sqlx_ (which is very low level btw) and will use more allocs.
667
668You must not think generic helpers of ``go-funk`` as a replacement when you are dealing with performance in your codebase,
669you should use typesafe implementations instead.
670
671Contributing
672------------
673
674* Ping me on twitter `@thoas <https://twitter.com/thoas>`_ (DMs, mentions, whatever :))
675* Fork the `project <https://github.com/thoas/go-funk>`_
676* Fix `open issues <https://github.com/thoas/go-funk/issues>`_ or request new features
677
678Don't hesitate ;)
679
680Authors
681-------
682
683* Florent Messa
684* Gilles Fabio
685* Alexey Pokhozhaev
686* Alexandre Nicolaie
687
688.. _reflect: https://golang.org/pkg/reflect/
689.. _lodash: https://lodash.com/
690.. _performance: https://github.com/thoas/go-funk/issues/19
691.. _gorm: https://github.com/jinzhu/gorm
692.. _sqlx: https://github.com/jmoiron/sqlx
693.. _godoc: https://godoc.org/github.com/thoas/go-funk
694