Post subject: Variant List Creator
Editor
Joined: 3/31/2010
Posts: 1466
Location: Not playing Puyo Tetris
I want a program that can do the following; I have a list of things. A, B and C. I have two options on how I want to list them. I can use Comma (,) or And. I want output that looks like this: A, B, C A, B and C A and B, C A and B and C When I put in A B C
When TAS does Quake 1, SDA will declare war. The Prince doth arrive he doth please.
Joined: 2/3/2013
Posts: 320
Location: Germany
I can't really think straight today for whatever reason and I'm sure, there's an obvious simplification in here, but I came up with this:
import Control.Monad (replicateM)

things :: [String]
things = ["A","B","C","D"]

delimiters :: [String]
delimiters = ["and", ","]

result = map (++ " D") combinations''' where
    combinations''' = map unwords combinations''
    combinations'' = map concat combinations'
    combinations' = map (map (\(x,y) -> [x,y])) combinations
    combinations = map (zip $ init things) $ replicateM (length things - 1) delimiters

main = putStr $ unlines result
runhaskell program ~>
A and B and C and D
A and B and C , D
A and B , C and D
A and B , C , D
A , B and C and D
A , B and C , D
A , B , C and D
A , B , C , D
I'm too lazy to do commandline parsing, and the result of this doesn't fit exactly what you imagined, but it's fixable (tell me if you want me to make a standalone program). The main logic is done by "map (zip $ init things) $ replicateM (length things - 1) delimiters". "replicateM (length things - 1) delimiters" creates the (length things - 1)-fold Carthesian product of delimiters with itself, so e.g. when the delimiters are ["and", ","] and the number is 3 the result will be
[["and","and","and"],
["and","and",","],
["and",",","and"],
["and",",",","],
[",","and","and"],
[",","and",","],
[",",",","and"],
[",",",",","]]
These represent all combinations of delimiters between the "things". The rest of that line creates a new list consisting of lists of tuples, where each inner list has tuples like ("A","and"), ("B",","), etc representing all the permutations that things and delimiters go together, one inner list per possibility:
[[("A","and"),("B","and"),("C","and")],
[("A","and"),("B","and"),("C",",")],
[("A","and"),("B",","),("C","and")],
[("A","and"),("B",","),("C",",")],
[("A",","),("B","and"),("C","and")],
[("A",","),("B","and"),("C",",")],
[("A",","),("B",","),("C","and")],
[("A",","),("B",","),("C",",")]]
The rest of the computation of "result" just converts this into a nicer-to-look-at string.
All syllogisms have three parts, therefore this is not a syllogism.
Editor
Joined: 3/31/2010
Posts: 1466
Location: Not playing Puyo Tetris
RGamma, I would like something that is written in .Net (C# or VB.Net) and supports up to, 13 items. If it doesn't output perfectly, that's fine. I can edit/adjust as I need to.
When TAS does Quake 1, SDA will declare war. The Prince doth arrive he doth please.
Joined: 2/3/2013
Posts: 320
Location: Germany
I can't help you with those languages, but maybe I can give you a hint on how to do it in an imperative style. If you have n (n>1) things and m (0<m<n) delimiters, then you'll need all combinations of those m delimiters of length n-1. So e.g. with A,B,C,D as your things and "and","," as delimiters, you need all combinations of "and" and "," of length 3 (D doesn't have a delimiter after it). One way to think about these combinations is counting. If we count in binary the numbers of length 3 it looks like: 000, 001, 010, ..., 110, 111. Likewise with delimiters it looks like: , , , | , , and | , and , | ... | and and , | and and and. You can see there's a straightforward mapping between the two (0 -> , and 1 -> and). So now we can count using our delimiters:
let things be the list of length n of things
let delims be the list of length m of delimiters
let result be the list of resulting strings
let counter be a base-m number with n-1 digits (initialised to 0)
repeat m^(n-1) times
    let temp be the mapping of counter to delims # e.g. 0 -> ","; 1 -> "and"; 101 becomes "and", ",", "and"
    intersperse elements of temp between things and add that to result # e.g. "A " + "and " + "B " + ", " + "C " + "and " + "D"
    increment counter # e.g. 101 -> 110
You could represent counter as e.g. normal integer, boolean integer (if the language offers that) or boolean array of proper length (for more delimiters the base of the counter needs to be higher of course, you could also cut out the middleman completely and directly count on your delimiters). With this I'm sure you can do the rest.
All syllogisms have three parts, therefore this is not a syllogism.
creaothceann
He/Him
Editor
Joined: 4/7/2005
Posts: 1874
Location: Germany
Hooray for recursion.
program Variant_List_Creator;  {$mode objfpc}  {$H+}


procedure p(const tmp : String;  const i : Integer);
begin
if (i > ParamCount) then begin
        WriteLn(tmp);
        exit;
end;
p(tmp + ', '    + ParamStr(i), i + 1);
p(tmp + ' and ' + ParamStr(i), i + 1);
end;


begin
if (ParamCount < 2) then begin
        WriteLn('Error: need at least 2 parameters');
        Halt(1);
end;
p(ParamStr(1), 2);
end.
Lazarus (i.e. FreePascal) project with binary: link
Editor
Joined: 3/31/2010
Posts: 1466
Location: Not playing Puyo Tetris
creaothceann wrote:
Hooray for recursion.
program Variant_List_Creator;  {$mode objfpc}  {$H+}


procedure p(const tmp : String;  const i : Integer);
begin
if (i > ParamCount) then begin
        WriteLn(tmp);
        exit;
end;
p(tmp + ', '    + ParamStr(i), i + 1);
p(tmp + ' and ' + ParamStr(i), i + 1);
end;


begin
if (ParamCount < 2) then begin
        WriteLn('Error: need at least 2 parameters');
        Halt(1);
end;
p(ParamStr(1), 2);
end.
Lazarus (i.e. FreePascal) project with binary: link
This worked great for what I needed. What I needed this for, is I am going to make a database (of a sort) of various commands I can enter into Z-Machine (Zork) like games. Example: I need to enter the commands; South wait Before I can proceed in the game. So what I wanted to find out, what entry is faster. I could tell the game, South and Wait then press enter. Or I could do South, press enter, then Wait then press enter. The issue is, I have a section in my TAS where I can enter 12 separate commands using And to "stack" those commands or "Chain" them together. Which one of those mixtures of And and pressing enter, is the fastest? I needed a way to track those variants. Now, to save all the frames.
When TAS does Quake 1, SDA will declare war. The Prince doth arrive he doth please.
Banned User, Former player
Joined: 3/10/2004
Posts: 7698
Location: Finland
Recursive implementations of these types of things are often sweet and short. Another possibility is to notice that you essentially have all possible combinations of (n-1) bits (where n is the number of elements). This means that if you increment an integer from 0 to 2n-1-1, then you can output each element and between them either a comma or "and" depending on the correspondent bit in the integer. OTOH the recursive implementation is probably more beautiful.
Joined: 2/3/2013
Posts: 320
Location: Germany
Warp wrote:
Recursive implementations of these types of things are often sweet and short. Another possibility is to notice that you essentially have all possible combinations of (n-1) bits (where n is the number of elements). This means that if you increment an integer from 0 to 2n-1, then you can output each element and between them either a comma or "and" depending on the correspondent bit in the integer. OTOH the recursive implementation is probably more beautiful.
That counting algorithm I described earlier. I also had one that used the monadic instance of a list in Haskell to do that. Both seem extremely overengineered compared to what creaothceann posted. At least my solutions work out of the box for any amount of delimiters, but it bugs me that I didn't suggest "the obvious" firsthand.
All syllogisms have three parts, therefore this is not a syllogism.
Banned User, Former player
Joined: 3/10/2004
Posts: 7698
Location: Finland
My "increment an integer and read its bits" solution only works up to the number of bits in the integer type (unless the programming language supports integers of unlimited size). If more bits than that are needed, then one would have to implement the increment operation on a table of bits manually, but it's not a difficult thing to do. (It's essentially: Increment the least significant bit, and if it wraps back to 0, go to the next bit and repeat until a bit doesn't wrap. It works with any base too. It's basically the odometer algorithm.)