This work is based on an original article called "15 Useful JS Examples of map(), reduce() and filter()" (https://medium.com/@alex.permyakov/15-useful-javascript-examples-of-map-reduce-and-filter-74cbbb5e0a1f ) by Alex Permyakov, 2019-1-16.
1. The examples on this page use the following libraries:
2. And the following assert procedure:
proc assert {args} { if {! [uplevel 1 expr $args]} { puts "FAIL -> $args" } else { puts "ok -> [list [lindex $args end]]" } }
set values {3 1 3 5 2 4 4 4} ::struct::set add uniques $values assert {$uniques eq {4 1 5 2 3}}
set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set res [::fptools::lfilter it $users {string match oli* [dict get $it name]}] assert {$res eq {}}
Or in plain Tcl 8.6:
set res [lmap it $users {if {[string match oli* [dict get $it name]]} {set it} else continue}] assert {$res eq {}}
set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set res [::fptools::lfilter it $users {string match -nocase oli* [dict get $it name]}] assert {[::struct::list equal $res {{id 97 name Oliver age 28 group admin}}]}
Or in plain Tcl 8.6:
set res [lmap it $users {if {[string match -nocase oli* [dict get $it name]]} {set it} else continue}] assert {[::struct::list equal $res {{id 97 name Oliver age 28 group admin}}]}
set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set hasAdmin [::fptools::lfilter it $users {string match admin [dict get $it group]}] assert {[llength $hasAdmin]}
Or in plain Tcl 8.6:
set hasAdmin [lmap it $users {if {[string match admin [dict get $it group]]} {set it} else continue}] assert {[llength $hasAdmin]}
set nested {{1 2 3} {{4 5} 6} {7 8 9}} set flat [::fptools::lflatten $nested 2] ;# 2 is the depth of flattening assert {[::struct::list equal $flat {1 2 3 4 5 6 7 8 9}]}
set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set groupByAge [::fptools::lreduce acc it [dict create] $users { dict incr acc [dict get $it age] }] assert {$groupByAge eq {23 1 28 2 34 1}}
set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set uTable [::fptools::lreduce acc it [dict create] $users { dict set acc [dict get $it id] $it }] assert {[::struct::list equal $uTable { 11 { id 11 name Adam age 23 group editor } 47 { id 47 name John age 28 group admin } 85 { id 85 name William age 34 group editor } 97 { id 97 name Oliver age 28 group admin } }]}
set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } lmap it $users {::struct::set add listOfUserGroups [dict get $it group]} assert {$listOfUserGroups eq {admin editor}}
set cities { Lyon France Berlin Germany Paris France } set countries [::fptools::lreduce acc it [dict create] [dict keys $cities] { dict lappend acc [dict get $cities $it] $it }] assert {[::struct::list equal $countries {France {Lyon Paris} Germany {Berlin}}]}
set celsius {-15 -5 0 10 16 20 24 32} set fahrenheit [lmap it $celsius {expr {$it * 1.8 + 32}}] assert {$fahrenheit eq {5.0 23.0 32.0 50.0 60.8 68.0 75.2 89.6}}
proc encodeURIComponent {elem} {return $elem} set params {lat 45 lng 6 alt 1000} set queryString [join [lmap {k v} $params {join [list [encodeURIComponent $k] [encodeURIComponent $v]] =}] &] assert {$queryString eq "lat=45&lng=6&alt=1000"}
set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set output [join [lmap it $users {lmap key {id age group} {dict get $it $key}}] \n] assert {$output eq "11 23 editor 47 28 admin 85 34 editor 97 28 admin"}
set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set updatedUsers [lmap it $users {expr {[dict get $it id] == 47 ? [dict incr it age] : $it}}] assert {[dict get [lindex $updatedUsers 1] age] == 29}
set arrA {1 4 3 2} set arrB {5 2 6 7 1} set res [::struct::set union $arrA $arrB] assert {[lsort $res] eq [lsort {1 4 3 2 5 6 7}]}
set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[::struct::set intersect $arrA $arrB] eq {1 2}}
set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[::struct::set difference $arrA $arrB] eq {4 3}}
set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[::struct::set difference $arrB $arrA] eq {5 6 7}}
set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[lsort [::struct::set symdiff $arrA $arrB]] eq [lsort {4 5 6 7 3}]}
set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[lsort [::struct::set symdiff $arrB $arrA]] eq [lsort {4 5 6 7 3}]}
#!/usr/bin/env tclsh # Useful examples of Functional Tcl # Barry Arthur, 2019-1-28 # Original Article: 15 Useful JS Examples of map(), reduce() and filter() # https://medium.com/@alex.permyakov/15-useful-javascript-examples-of-map-reduce-and-filter-74cbbb5e0a1f # by Alex Permyakov, 2019-1-16. package require struct::set package require struct::list package require fptools # # Testing Helpers # proc Example {args} { set ::eg [concat $args] } proc assert {args} { if {! [uplevel 1 expr $args]} { puts "FAIL $::eg\n-> $args" } else { puts "ok $::eg\n-> [list [lindex $args end]]" } } # # Functional Examples # Example 1. Remove duplicates from an array of numbers/strings set values {3 1 3 5 2 4 4 4} ::struct::set add uniques $values assert {$uniques eq {4 1 5 2 3}} Example 2. A simple search (case-sensitive) set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set res [::fptools::lfilter it $users {string match oli* [dict get $it name]}] assert {$res eq {}} # # Or in plain Tcl 8.6: # set res [lmap it $users {if {[string match oli* [dict get $it name]]} {set it} else continue}] assert {$res eq {}} Example 3. A simple search (case-insensitive) set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set res [::fptools::lfilter it $users {string match -nocase oli* [dict get $it name]}] assert {[::struct::list equal $res {{id 97 name Oliver age 28 group admin}}]} # # Or in plain Tcl 8.6: # set res [lmap it $users {if {[string match -nocase oli* [dict get $it name]]} {set it} else continue}] assert {[::struct::list equal $res {{id 97 name Oliver age 28 group admin}}]} Example 4. Check if any of the users have admin rights set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set hasAdmin [::fptools::lfilter it $users {string match admin [dict get $it group]}] assert {[llength $hasAdmin]} # # Or in plain Tcl 8.6: # set hasAdmin [lmap it $users {if {[string match admin [dict get $it group]]} {set it} else continue}] assert {[llength $hasAdmin]} Example 5. Flattening an array of arrays set nested {{1 2 3} {{4 5} 6} {7 8 9}} set flat [::fptools::lflatten $nested 2] ;# 2 is the depth of flattening assert {[::struct::list equal $flat {1 2 3 4 5 6 7 8 9}]} Example 6. Create an object that contains the frequency of the specified key set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set groupByAge [::fptools::lreduce acc it [dict create] $users { dict incr acc [dict get $it age] }] assert {$groupByAge eq {23 1 28 2 34 1}} Example 7. Indexing an array of objects (lookup table) set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set uTable [::fptools::lreduce acc it [dict create] $users { dict set acc [dict get $it id] $it }] assert {[::struct::list equal $uTable { 11 { id 11 name Adam age 23 group editor } 47 { id 47 name John age 28 group admin } 85 { id 85 name William age 34 group editor } 97 { id 97 name Oliver age 28 group admin } }]} Example 8. Extract the unique values for the given key of each item in the array set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } lmap it $users {::struct::set add listOfUserGroups [dict get $it group]} assert {$listOfUserGroups eq {admin editor}} Example 9. Object key-value map reversal set cities { Lyon France Berlin Germany Paris France } set countries [::fptools::lreduce acc it [dict create] [dict keys $cities] { dict lappend acc [dict get $cities $it] $it }] assert {[::struct::list equal $countries {France {Lyon Paris} Germany {Berlin}}]} Example 10. Create an array of Fahrenheit values from an array of Celsius values set celsius {-15 -5 0 10 16 20 24 32} set fahrenheit [lmap it $celsius {expr {$it * 1.8 + 32}}] assert {$fahrenheit eq {5.0 23.0 32.0 50.0 60.8 68.0 75.2 89.6}} Example 11. Encode an object into a query string proc encodeURIComponent {elem} {return $elem} set params {lat 45 lng 6 alt 1000} set queryString [join [lmap {k v} $params {join [list [encodeURIComponent $k] [encodeURIComponent $v]] =}] &] assert {$queryString eq "lat=45&lng=6&alt=1000"} Example 12. Print a table of users as a readable string only with specified keys set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set output [join [lmap it $users {lmap key {id age group} {dict get $it $key}}] \n] assert {$output eq "11 23 editor 47 28 admin 85 34 editor 97 28 admin"} Example 13. Find and replace key-value pair in an array of objects set users { { id 11 name Adam age 23 group editor } { id 47 name John age 28 group admin } { id 85 name William age 34 group editor } { id 97 name Oliver age 28 group admin } } set updatedUsers [lmap it $users {expr {[dict get $it id] == 47 ? [dict incr it age] : $it}}] assert {[dict get [lindex $updatedUsers 1] age] == 29} Example 14. Union (A ∪ B) of arrays set arrA {1 4 3 2} set arrB {5 2 6 7 1} set res [::struct::set union $arrA $arrB] assert {[lsort $res] eq [lsort {1 4 3 2 5 6 7}]} Example 15. Intersection (A ∩ B) of arrays set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[::struct::set intersect $arrA $arrB] eq {1 2}} Example 16. Difference (A - B) of arrays set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[::struct::set difference $arrA $arrB] eq {4 3}} Example 17. Difference (B - A) of arrays set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[::struct::set difference $arrB $arrA] eq {5 6 7}} Example 18. Symmetric Difference (A -- B) of arrays set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[lsort [::struct::set symdiff $arrA $arrB]] eq [lsort {4 5 6 7 3}]} Example 19. Symmetric Difference (B -- A) of arrays set arrA {1 4 3 2} set arrB {5 2 6 7 1} assert {[lsort [::struct::set symdiff $arrB $arrA]] eq [lsort {4 5 6 7 3}]}