How to do Permutations in numbers. Not just the of possible permutations but the actual combinations.

How to do Permutations in numbers. Not just the number of possible permutations but the actual combinations of those possible permutations.

For example: A, B, C

3!= 6

I would like to know how to get this in numbers. Instead of just 6.

a b c

1 A, B, C

2 A, C, B

3 B, A, C

4 B, C, A

5 C, A, B

6 C, B, A

Posted on May 15, 2014 8:58 PM

Reply
23 replies

May 15, 2014 9:42 PM in response to DwightW.Tarrago

Hello


I don't know of any simple method to generate permutations in Numbers.


If you are fine using AppleScript, here's a script to generate permutations of given set of elements as tab delimited text in clipboard, which you may paste into Numbers table.


Copy the code listed below into new window of AppleScript Editor.app and run it. It will ask you to enter a set of elements, such as ABC, and then it will generate its permutations and put its TSV representation in clipboard. You may give repeated elements such as AAB and it will generate permutations as AAB, ABA, BAA.



_main()
on _main()
    display dialog "Enter elements" default answer "ABC"
    set xx to text returned of result
    set yy to permutation(xx, count xx)
    set t to _array2text(yy, tab, return)
    set the clipboard to t
    return t
end _main

on permutation(xx, n) -- v1.0f1
    (*
        list xx: list of items
        int n: number of items in each permutation
        return list: list of permutations
        
        * xx may contain repeated elements
    *)
    script o
        property pp : xx's contents
        property ppl : (count my pp)
        property qq : {}
        property rr : {}
        
        if n = 0 then return {}
        if n = 1 then
            repeat with p in my pp
                set p to p's contents
                if {p} is not in my qq then set end of my qq to p
            end repeat
            return my qq's contents
        end if
        
        repeat with i from 1 to ppl
            set p to my pp's item i
            if {p} is in my qq then -- prune this branch
            else
                if i = 1 then
                    set yy to {}
                else
                    set yy to my pp's items 1 thru (i - 1)
                end if
                if i < ppl then set yy to yy & my pp's items (i + 1) thru -1
                -- yy = pp - {p}
                repeat with r in permutation(yy, n - 1)
                    set end of my rr to {p} & r's contents
                end repeat
                set end of my qq to p -- add to prune list
            end if
        end repeat
        return my rr's contents
    end script
    tell o to run
end permutation

on _array2text(aa, cs, rs)
    (*
        list aa : source 2d-array
        string cs : column separator (field separator)
        string rs : row separator (record separator)
        return string : text representation of aa
    *)
    script o
        property pp : aa
        property qq : {}
        repeat with p in my pp
            set end of my qq to _join(p's contents, cs)
        end repeat
        return _join(qq, rs)
    end script
    tell o to run
end _array2text

on _join(tt, d)
    (*
        list tt : source list
        string d : separator
        return string : tt joined with d
    *)
    local astid, astid0, t
    set astid to a reference to AppleScript's text item delimiters
    try
        set {astid0, astid's contents} to {astid's contents, {} & d}
        set t to "" & tt
        set astid's contents to astid0
    on error errs number errn
        set astid's contents to astid0
        error errs number errn
    end try
    return t
end _join


Hope this may help,

H

May 16, 2014 12:56 PM in response to E.Orduna

Hello


Theoretically you can replace the _main() handler of the previous script with something like the following one to treat multi-character element. BUT poor AppleScript is unacceptably slow to generate the permutations of 8 elements, that is of size 8! = 40320.


on _main()
    display dialog "Enter elements" default answer "X XY 1 12 J 2 3 4"
    set xx to words of text returned of result
    set yy to permutation(xx, count xx)
    set t to _array2text(yy, tab, return)
    set the clipboard to t
    return t
end _main



Here's another AppleScript script which is actually a simple wrapper of fast ruby script. You may separate each element by space(s) in dialogue. It will put the TSV result in clipboard.


_main()
on _main()
    display dialog "Enter elements" default answer "X XY 1 12 J 2 3 4"
    set t to text returned of result

    do shell script "/usr/bin/ruby -w <<'EOF' - " & t & "
def permutation(aa, n)
    #     array aa : list of elements
    #     int n : number of elements in each permutation
    #     return array : array of permutations
    #     
    #     * aa may contain repeated elements
    bb, cc = [], []
    return [] if n < 1
    if n == 1
        aa.each {|a| bb << [a] unless bb.include?(a)}
        return bb
    end
    (0 .. aa.length - 1).each do |i|
        a = aa[i]
        if bb.include?(a)    # prune this branch
        else
            aa1 = aa.dup
            aa1.slice!(i)
            permutation(aa1, n - 1).each {|c| cc << [a] + c}
            bb << a            # add this to prune list
        end
    end
    return cc
end

def array2text(aa, fs, rs)
    #     array aa : 2-d array
    #     string fs : field separator
    #     string rs : record separator
    return aa.map {|a| a.join(fs) }.join(rs)
end

pp = permutation(ARGV, ARGV.length)
puts array2text(pp, %[\\t], %[\\n])
EOF"
    set r to result
    set the clipboard to r
    return r
end _main


Hope this may help,

H

May 16, 2014 2:37 PM in response to Hiroto

Hi H,


Great scripts! Thanks.


Your 'default answer' data in the second one (the Ruby wrapper) results in such a big clipboard that neither Numbers 2 nor Numbers 3 can handle it on my machine.


I tried with fewer elements and it works well!


Very basic question. Can you briefly explain the use of result?


I understand


set t to text returned of result


after the dialog.


But how does


set r to result

work after the Ruby Script?


How does the output of the Ruby script "get into"result ?


Thanks!


SG

May 16, 2014 3:29 PM in response to SGIII

Hello SG,


The "result" in AppleScript holds anything returned in the last statement and the "do shell script" command returns anything written to stdout in shell script (when exit status of shell script is 0).


E.g.,


do shell script "echo hello"
set r to result
return r -- "hello"


And the puts function in Ruby puts the string followed by linefeed to stdout.


E.g,


do shell script "ruby <<'EOF'
puts \"hello\"
EOF"
set r to result
return r -- "hello"


---

By the way, I've not actually tried to paste the 40320 lines TSV text into Numbers (v2) and yes, it fails (or possibly I'm not patient enough to wait for the completion...)


So here's a variation of the script that will save the result to CSV file as you choose in dialogue. In brief test, I can successfully open the CSV file in Numbers v2.



_main()
on _main()
    display dialog "Enter elements" default answer "X XY 1 12 J 2 3 4"
    set t to text returned of result
    set f to (choose file name default name "permutations.csv" default location (path to desktop))'s POSIX path
    
    do shell script "/usr/bin/ruby -w <<'EOF' - " & t & " > " & f's quoted form & "
def permutation(aa, n)
    #     array aa : list of elements
    #     int n : number of elements in each permutation
    #     return array : array of permutations
    #     
    #     * aa may contain repeated elements
    bb, cc = [], []
    return [] if n < 1
    if n == 1
        aa.each {|a| bb << [a] unless bb.include?(a)}
        return bb
    end
    (0 .. aa.length - 1).each do |i|
        a = aa[i]
        if bb.include?(a)    # prune this branch
        else
            aa1 = aa.dup
            aa1.slice!(i)
            permutation(aa1, n - 1).each {|c| cc << [a] + c}
            bb << a            # add this to prune list
        end
    end
    return cc
end

def array2text(aa, fs, rs)
    #     array aa : 2-d array
    #     string fs : field separator
    #     string rs : record separator
    return aa.map {|a| a.join(fs) }.join(rs)
end

pp = permutation(ARGV, ARGV.length)
puts array2text(pp, %[,], %[\\n])
EOF"
end _main



All the best,

H

May 17, 2014 12:28 AM in response to Hiroto

Hey! Thanks for your help!


Unfortunately this script was not correct for my task, as I framed it wrong. I did however find a solution. I found the list elsewhere and copy and pasted it 🙂.


What I really needed was to find a way to create a possible combination for a set of products.


For example:


Product A:

Tall, Black, Has feature 1, No Feature 2, Feature 3 Type A


Product B

Tall, Black, Has no feature 1,Has feature 2, Has Feature 3 Type A



Where Tall is , there is also Short and Wide

Where Black is there is also White and Cream



Am I just being stupid, or can your script also work for this?


many thanks,


E

May 17, 2014 6:49 AM in response to E.Orduna

You can do using a script of some kind (AppleScript, Perl, Python) or a simple command line program. You can also use multiple tables that are configurable like this:


User uploaded file


The table "Set Up" (on the right) is for entering the categories and the items in each category. The way things are set up it is better to insert new columns to the left (BEFORE column A).


The table "Information" (on the left) is a quick summary of the entries for use in later steps.

A1=IFERROR(OFFSET(Set up::$A$1, COLUMN()−1, ROW()−1), "")


this is shorthand for... select cell A1, then type (or copy and paste from here) the formula:

=IFERROR(OFFSET(Set up::$A$1, COLUMN()−1, ROW()−1), "")

B1=IF(A1="", "", COUNTA(OFFSET(Set up::$A, 0, MATCH(A1, Set up::$1:$1,0)−1, ROWS(Set up::A), 1))−1)


select A1 and B1, copy

select columns A and B, paste


add a footer row (in this example, then footer row is row 11)

B11=PRODUCT(B)



now let's make the combinations. Create a table called "Combinations" like this:

User uploaded file

Make the Combination table (as shown above).


The first two rows are header rows.

B2=OFFSET(Information::$A$1, COLUMN()−2, 0)

B1=VLOOKUP(B2,Information::$A:$B, 2, 0)


select B1 and B2, copy

select cells B1 thru G2, paste


A3=ROW()−2

B3=IF($A3≤Information::$B$11, MOD(INT((ROW()−3)÷PRODUCT(C$1:$G$1)), B$1), "")


select B3, copy

select B3 thru F3, paste

G3=IF(A3≤Information::$B$11, MOD((ROW()−3),G$1), "")


select A3 thru G3, copy


now select row 3 and type the key combination <option> + <down arrow> (to add a new row)

select row 3, copy

select row 4, paste

now select rows 3 and 4, and type the key combination <option> + <down arrow>


now select rows 3 thru 6 and type the key combination <option> + <down arrow>

now select rows 3 thru 10 and type the key combination <option> + <down arrow>

now select rows 3 thru 18 and type the key combination <option> + <down arrow>

now select rows 3 thru 34 and type the key combination <option> + <down arrow>

now repeatedly type the key combination <option> + <down arrow> until there is at least the number of rows shown in Information Table (last row)



If you want to see the actual names for the combinations you can add another table by selecting the table "Combination", then select the menu item "Edit > Duplicate Selection"


Name this new table "List" (or what ever you want):

leave row 2 as is.


B1=MATCH(B2,Set up::$1:$1,0)

select B1, copy

select B1 thru G1, paste


A3=ROW()−2

B3=IF($A3≤Information::$B$11, OFFSET(Set up::$A$2, Combinations::B3, B$1−1), "")

select B3, copy,

select B3 thru G3, paste


select the whole table, then unselect rows 1 and 2 by holding the command key, then click row header 1, then 2, paste

May 17, 2014 11:27 AM in response to E.Orduna

Hello


Are you trying to get direct product of given sets?


E.g., given xx = {{0, 1}, {2, 3, 4}}, result = {{0, 2}, {0, 3}, {0, 4}, {1, 2}, {1, 3}, {1, 4}} ?


If so, you may use something like the following applescript which is wrapper of ruby script.


This one will put the result in clipboard:


_main()
on _main()
    display dialog "Enter sets, each per line" default answer "A B C" & return & "0 1" & return & "XX XY"
    set xx to paragraphs of text returned of result
    set args to ""
    repeat with x in xx
        if (count x) > 0 then set args to args & x's quoted form & space
    end repeat

    do shell script "/usr/bin/ruby -w <<'EOF' - " & args & "
def array2text(aa, fs, rs)
    #     array aa : 2-d array
    #     string fs : field separator
    #     string rs : record separator
    return aa.map {|a| a.join(fs) }.join(rs)
end

aa = ARGV.map {|a| a.split}
a = aa.slice!(0)
pp = a ? a.product(*aa) : []
puts array2text(pp, %[\\t], %[\\n])
EOF"
    set r to result
    set the clipboard to r
    return r
end _main



And this one will save the result to a CSV file of your choice.


_main()
on _main()
    display dialog "Enter sets, each per line" default answer "A B C" & return & "0 1" & return & "XX XY"
    set xx to paragraphs of text returned of result
    set f to (choose file name default name "direct_product.csv" default location (path to desktop))'s POSIX path
    set args to ""
    repeat with x in xx
        if (count x) > 0 then set args to args & x's quoted form & space
    end repeat

    do shell script "/usr/bin/ruby -w <<'EOF' - " & args & " > " & f's quoted form & "
def array2text(aa, fs, rs)
    #     array aa : 2-d array
    #     string fs : field separator
    #     string rs : record separator
    return aa.map {|a| a.join(fs) }.join(rs)
end

aa = ARGV.map {|a| a.split}
a = aa.slice!(0)
pp = a ? a.product(*aa) : []
puts array2text(pp, %[,], %[\\n])
EOF"
end _main


Regards,

H


PS. Next time plesee start new thread for your own question which is different than the original. 🙂


Message was edited by: Hiroto (added PS)

May 19, 2014 10:03 AM in response to Wayne Contello

Hi! I think I'm doing something wrong.

Where as your Information Chart total anumber of combinations is B11. mine is B8. So I've replaced that accordingly in the formula.

Secondly where as yours ends in G, mine has an extra column H. Also replaced this accordingly. However It keeps saying there is a syntaxtual error and I can not figure it out!


For B3

=IF($A3≤Summary::$B$8, MOD(INT((ROW()−3)÷PRODUCT(C$1:$H$1)), B$1), "")


For H3

=IF(A3≤Summary::$B$8, MOD((ROW()-3),H$1), "")

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

How to do Permutations in numbers. Not just the of possible permutations but the actual combinations.

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.