Home   Archive   Permalink



I need some help finishing this small program

R E B O L []
names: ["as" "br" "ch" "fr" "sp" "st" "su" "sv" "ts" "wh"]
everypossiblenonredundantcombinationofnamesinalphabeticalorder: []
forall names [
     if greater? length? names 1 [
         append everypossiblenonredundantcombinationofnamesinalphabeticalorder rejoin [first names " / " second names]
     ]
]
alert mold everypossiblenonredundantcombinationofnamesinalphabeticalorder
    
the goal is to have a list like
    
["as / br" "as / ch" "as / fr" {etc} "br / ch" "br / fr" "br / sp" {etc}]
    
it should NOT contain ["br / as" "cr / as" "ch / br" {etc}]
    
I think I'm on the right track with what I have written so far, but I need a little help finishing it.
    
Thanks for any advice !

posted by:   Andrew     2-Oct-2017/14:25:22-7:00



I think you're on the right track. FORALL is a good start point and if your NAMES block is always in alphabetical order, then you can always skip the current position and FOREACH on every subsequent value to get the combinations beginning with the value at the current position:
    
R ebol []
names: ["as" "br" "ch" "fr" "sp" "st" "su" "sv" "ts" "wh"]
probe everypossiblenonredundantcombinationofnamesinalphabeticalorder: collect [
     forall names [
         foreach name next names [
             keep rejoin [names/1 " / " name]
         ]
     ]
]

posted by:   Chris     2-Oct-2017/15:02-7:00



Thank you, Chris. I was trying to put an until loop inside the forall loop, then at the end of the until loop, doing remove/part, but I couldn't get it to work. I really appreciate the help, Chris, thanks.

posted by:   Andrew     2-Oct-2017/15:36:41-7:00



No problem. You could likely do it with another combination of loops, but this pair are fairly concise.

posted by:   Chris     2-Oct-2017/15:55:15-7:00



n: ["as" "br" "ch" "fr" "sp" "st" "su" "sv" "ts" "wh"]
x: copy []
foreach i n [foreach j n [if i < j [append x rejoin [i " / " j]]]]
probe x halt

posted by:   Nick     2-Oct-2017/23:38:20-7:00



Greater than and less than evaluations can be performed on the string type. This allows for a simpler solution, and eliminates the need for the list to be pre-sorted.

posted by:   Nick     3-Oct-2017/9:05:08-7:00



I should probably use collect/keep more often (although this won't work in older versions of Rebol, and honestly isn't much more concise):
    
n: ["as" "br" "ch" "fr" "sp" "st" "su" "sv" "ts" "wh"]
z: collect[foreach i n [foreach j n [if i < j [keep rejoin [i " / " j]]]]]

posted by:   Nick     3-Oct-2017/11:09:45-7:00



Just to show this doesn't rely on having a sorted block to start with:
    
n: random ["as" "br" "ch" "fr" "sp" "st" "su" "sv" "ts" "wh"]
z: collect[foreach i n [foreach j n [if i < j [keep rejoin [i " / " j]]]]]
sort copy z

posted by:   Nick     3-Oct-2017/11:18:23-7:00



Nick, 'older versions of Rebol'--works consistently on 2.7.8, Red, Rebol 3, and is very concise. Which older versions of Rebol are worth compromising for?

posted by:   Chris     9-Oct-2017/17:43:33-7:00



I didn't say it shouldn't be used, just noted that it's not available in old versions.

posted by:   Nick     10-Oct-2017/1:11:15-7:00



(I spoke with a friend during the past week who wants to try Rebol/View on Solaris - not sure if any version for that OS has 'collect, for example)

posted by:   Nick     10-Oct-2017/1:19:45-7:00



And, btw, it's true that this:
    
n: ["as" "br" "ch" "fr" "sp" "st" "su" "sv" "ts" "wh"]
z: collect[foreach i n [foreach j n [if i < j [keep rejoin [i " / " j]]]]]
    
actually isn't more concise than this:
    
n: ["as" "br" "ch" "fr" "sp" "st" "su" "sv" "ts" "wh"] x:[]
foreach i n [foreach j n [if i < j [append x rejoin [i " / " j]]]]
    
In fact, in this case, the 'collect example is less concise, and in many cases, in which something like x:[] can be defined inline, that option is even more concise. I made no general argument, and in fact, presented the updated example explicitly with the explanation that I "should probably use collect/keep more often".

posted by:   Nick     10-Oct-2017/1:32:55-7:00



I do something like this all the time:
    
foreach i system/locale/months [append x:[] join i " "] probe x
    
Instead of:
    
x: collect [foreach i system/locale/months [keep join i " "]] probe x

posted by:   Nick     11-Oct-2017/5:22:47-7:00



Since functions like 'append, and the definition of blocks are fundamental to the structure of the language, I assume it's still a good idea for people learning Rebol-like languages to understand and be able to use those constructs, even if 'higher level' options are available. For the first few years, Red didn't even have basic functions such as 'rejoin, and I haven't checked recently, but not sure if Boron or World have 'collect.

posted by:   Nick     11-Oct-2017/5:35:05-7:00



I would absolutely introduce APPEND as a foundational function in Rebol, no argument there. However I'd contend that COLLECT/KEEP is a more appropriate--and objectively concise--choice for basic (where MAP-EACH--not in Red--doesn't apply) and moderately complex list comprehensions such as that presented by the OP.
    
I'd measure concision as a combined function of brevity and clarity.
    
In terms of pure size--the only cost to COLLECT/KEEP is the initial COLLECT and first usage of KEEP (assuming a one-letter variable for the APPEND alternative). Thereafter KEEP will always be shorter than APPEND X. Moreover if you are concerned with naming then you are already behind:
    
     COLLECT [KEEP 'foo]
     words: [] APPEND words 'foo
    
It's in the expressivity of COLLECT/KEEP that I find the real value:
    
* it is contextual--you find COLLECT and the comprehension happens within that space. For me, COLLECT is hyper-versatile analogue to the likes of REDUCE or COMPOSE.
    
* it reduces repetition: `append x` becomes `keep` (this consideration for me goes beyond size).
    
* the product is always returned: in cases where you gather conditionally within a loop.
    
* does not need a tracking variable--no X: or WORDS: etc.
    
I'll not say it's without its limitations though—COLLECT/KEEP is not effective when you need to dispatch values to multiple destinations.
    
Anyways: if it's not clear, I found COLLECT/KEEP to be a boon when it was introduced and heartily endorse its usage. It's dismaying to think that there's any version of Rebol older than 2.7.8 (itself dated Jan 2011!) that would have any bearing on which expressions a newbie uses--although often, as with COLLECT, you can copy the SOURCE and add it to user.r to patch the missing functionality.
    
As an aside, I'd note that the following breaks in Ren-C as literally created series are locked by default:
    
     foreach i system/locale/months [append x: [] join i " "] probe x
    
X: COPY [] APPEND X 'FOO still works though.

posted by:   Chris     11-Oct-2017/18:45:58-7:00



Those are all great arguments - thanks Chris :)

posted by:   Nick     11-Oct-2017/20:53:47-7:00