One liner does the unexpected (because I'm new?)
f: Is a list of first names l: Is a list of last names >> append voters join pick f random length? "+" f pick l random length? l ** Script Error: John has no value ** Where: repend ** Near: John David Michael Chris Mike Without the "+" >> append voters join pick f random length? f pick l random length? l == ["PaulBouck" "JoanneRodriguez" "CarolLerner" "ChrisRodriguez" "AliceGriffin" "JamesLerner"] What I need is to join a "+" between the first and last name. I will clean this up... I was just playing with what can be done in one line 'without' compose. It also brings up the question: Does REBOL has a function like ruby's Array#Zip ? x: [2 4 6 8] y: [1 3 5 7] z: zip y x == [1 2 3 4 5 6 7 8]
posted by: Gus (gt) 7-Aug-2013/20:25:33-7:00
OOPS... noticed the typo. The unexpected is this: >> append voters join pick f random length? f "+" pick l random length? l == Griffin >> voters == ["Betty+"]
posted by: Gus (gt) 7-Aug-2013/20:27:40-7:00
haha! join join That's cute :) append voters join join pick f random length? f "+" pick l random length? l == ["Daniel+Johnson" "Mark+Garcia" "Erica+Lerner" "Erica+Case"] lol
posted by: Gus (gt) 7-Aug-2013/20:30:04-7:00
There are some functions to do that: b: ["one" "two" "three"] rejoin b ;== "onetwothree" reform b ;== "one two three" ajoin b ;== "onetwothree" So you can do that: reform ["one" "+" "two"] ;== "one + two" join "one" "+" ;== "one+" etc.
posted by: Endo 8-Aug-2013/10:45:17-7:00
Here I wrote a MERGE function which merges the given block: merge: func [ "Merge a block using a delimiter. Default is coma." b [block!] "Block to merge." /with c [char! string! none!] "Delimiter char or string." /tab "Merge with tab (shortcut)" ][ if empty? b [return copy ""] c: to-string any [c if tab ["^-"] ","] head clear skip foreach x b [insert tail s: "" join form x c] negate length? c ] merge/with b " + " ;== "one + two three" merge b ;==one,two,three
posted by: Endo 8-Aug-2013/10:47:01-7:00
REBOL needs a built in function that interleaves two blocks. It doesn't sound that useful, but it's surprising how handy it is to have. Called "zip" in python or ruby. Or "zip_ with"
posted by: Gus 8-Aug-2013/13:21:04-7:00
You can simply use APPEND, x: [1 2 3] y: [4 5 6] append x y ;== [1 2 3 4 5 6] Notice that it modifies X. if you don't want to modify X then you should COPY it: append copy x y One last thing, you don't need to "pick random x 1" You can simply use RANDOM/ONLY random/only [1 2 3 4] ;==3
posted by: Endo 8-Aug-2013/18:43:12-7:00
Endo, you are the best
posted by: Gus 8-Aug-2013/20:12:29-7:00
Theoretically it would work like this. x: [1 3 21 32] y: [blue red cow water] zip x y ;== [1 blue 3 red 21 cow 32 water] zip y x ;== [blue 1 red 3 cow 21 water 32] You're still the best :) Thanks for the replies.
posted by: Gus 8-Aug-2013/21:43:39-7:00
R E B O L [] zip: func [b1 b2 /local temp] [ temp: copy [] repeat x max length? b1 length? b2 [ if not none = f1: pick b1 x [append temp f1] if not none = f2: pick b2 x [append temp f2] ] temp ] probe zip [1 2 3] [4 5 6 7] probe zip [4 5 6 7] [1 2 3] probe zip system/locale/months system/locale/days probe zip system/locale/days system/locale/months halt
posted by: Nick 11-Aug-2013/7:48:07-7:00
Hey Nick, that's pretty clean looking. Why do you add halt at the end of your scripts?
posted by: Gus 11-Aug-2013/19:36:08-7:00
Just in case someone tries to paste the code into a text file and run by double clicking the icon, run from REBOL's text editor, etc. If you run from a script file (as opposed to pasting directly into REBOL's console), the program will run and close, before you have time to see the results. I've had so many people over the years contact me about scripts "not running" properly, that I now just toss that in by default :)
posted by: Nick 12-Aug-2013/9:49:10-7:00
Here I a little bit improved Nick's ZIP function, zip: func [ "Combine two blocks" b1 [block!] b2 [block!] /pad "Include none values" /local temp ] [ temp: copy [] repeat x max length? b1 length? b2 [ if any [ f1: pick b1 x pad not tail? at b1 x ] [append temp f1] if any [ f2: pick b2 x pad not tail? at b2 x ] [append temp f2] ] temp ] Nick's version was not safe if there is none values inside the blocks, none values was not included in the result block anyway: Here are some test: x: compose [1 2 3 (none)] y: compose [(none) a b c d e] ;notice that none values! ;Nick's version; >> zip x y == [1 2 a 3 b c d e] ;none values removed The version above; >> zip x y == [1 none 2 a 3 b none c d e] And I've added /pad refinement to be able to combine even if one of the blocks has more item than the other. >> zip/pad x y == [1 a 2 b 3 c none d none e] So the result block has always even number of values, safe to use with FOREACH: FOREACH [a b] zip x y [] >> zip [1 2] [a] == [1 a 2] >> zip/pad [1 2] [a] == [1 a 2 none] >> zip/pad [] [a] == [none a] Credit goes to Nick, I just improved a bit.
posted by: Endo 13-Aug-2013/8:11:52-7:00
Oh f1 and f2 should be added to /local zip: func [ "Combine two blocks" b1 [block!] b2 [block!] /pad "Include none values" /local temp f1 f2 ] [...]
posted by: Endo 13-Aug-2013/8:14:07-7:00
By the way it would be nice try to write a ZIP function to combine *any* number of blocks. Something like: x: [1 2] y: [a b c] z: [p q] >> zip reduce [x y z] == [1 a p 2 b q none c none]
posted by: Endo 13-Aug-2013/8:24:47-7:00
I'd imagine you would have to have, [blks [block!]] Then set your locals 'f join index of each block within the blks block. JavaScript is one language where it doesn't care how many args you supply to a function, and you see a common for loop pattern used to handle the arg count supplied. In REBOL, I suspect you might use length? And check if its not at the end of the arg list. ?
posted by: Gus 16-Aug-2013/18:14:51-7:00
In Rebol we usually use one (reduced) block argument to supply any number of arguments for a function: f: func [b [block!] "Block of arguments (reduced)"] [ foreach v reduce b [probe v] ] So we can use it as below: >> a: 5 b: "x" c: [a] >> f [a b c] And sometimes it is better to use COMPOSE instead of REDUCE: f: func [b [block!] "Block of arguments (reduced)"] [ foreach v compose/only b [probe v] ] So you can use it like: >> a: 5 b: "x" c: [a] >> f [a (b) c] == a "x" c ;note that only B evaluated
posted by: Endo 27-Aug-2013/4:33:46-7:00
Here's a repost from my answer in the "function arity" topic, along the same lines. This allows you to have any number of arguments lists, each with any number of items: myFunc: func [blks] [ foreach blk blks [ count: 1 foreach b blk [ print rejoin [ "Item #" count " in " mold blk ": " ] ++ count ] ] ] myFunc [[1 2 3] [x y z] [2 4 6]] halt
posted by: Nick 28-Aug-2013/13:06:30-7:00
Here's a repost from my answer in the "function arity" topic, along the same lines. This allows you to have any number of arguments lists, each with any number of items: myFunc: func [blks] [ foreach blk blks [ count: 1 foreach b blk [ print rejoin [ "Item #" count " in " mold blk ": " ] ++ count ] ] ] myFunc [[1 2 3] [x y z] [2 4 6]] halt
posted by: Nick 28-Aug-2013/13:06:33-7:00
|