Case Permutation

27

Who needs to compare things case insensitively when you're able to generate every permutation of uppercase and lowercase? No one! That's the answer. No one does. Your task is to achieve this feat; generate all possible permutations of uppercase/lowercase for a given input.

Input

A string of printable standard ascii characters. Input should not be assumed to be all lowercase. Input will always be at least one character.

Output

Every permutation of uppercase and lowercase for the inputted string (no duplicates). This should only change characters with a small and large version (numbers will stay the same). Each permutation must be output as a string or a list of characters; lists of singleton strings are not allowed.

Examples

a1a
['a1a', 'a1A', 'A1a', 'A1A']

abc
['abc', 'abC', 'aBc', 'aBC', 'Abc', 'AbC', 'ABc', 'ABC']

Hi!
['hi!', 'hI!', 'Hi!', 'HI!'] 

Scoring

This is , so the shortest answer (in bytes) wins.

As a fun extra see how much additional effort it will take to handle the extended ascii characters, here is an extra test case:

ž1a -> ['ž1a', 'ž1A', 'Ž1a', 'Ž1A']

(your program does not need to support this)

Poke

Posted 2016-05-31T13:17:26.517

Reputation: 3 075

10Interesting Unicode test case: Σ['Σ', 'σ', 'ς'] – n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ – 2016-06-01T03:20:35.527

Can we use a list of characters instead of a string? For example, if Hi! gave {('H', 'i', '!'), ('h', 'I', '!'), ('h', 'i', '!'), ('H', 'I', '!')} would that be acceptable? – James – 2016-06-01T06:21:45.213

@DrGreenEggsandHamDJ List of characters are allowed by default. In Python, those are singleton strings though, which is different.

– Dennis – 2016-06-01T07:01:54.130

@DrGreenEggsandHamDJ I would tend to agree with Dennis here. I didn't want to be too specific in the spec in order to not inadvertently exclude languages based on their output and wanted to make sure something like a list of characters was allowed. However I don't think singleton strings fit the bill in this case. – Poke – 2016-06-01T13:21:02.780

1@n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ even more interesting is that Σ is the uppercase version at the beginning of a word, σ is the lowercase version at the beginning or in the middle but not the end of a word, and ς is the lowercase version at only the end of a word. – FantaC – 2017-12-14T15:23:25.877

I know this is pretty old but when outputting strings, is it acceptable to output a trailing space at the end of the line? – Dom Hastings – 2018-05-01T19:06:24.833

1@DomHastings As in you have a list and you're just space-delimiting the output? That seems reasonable to me. – Poke – 2018-05-01T19:42:44.923

Answers

11

Pyth, 13 12 11

{msrVQd^U2l

1 byte thanks to Leaky Nun!

Another byte thanks to Jakube!

Try it here or run a Test Suite

We create a list of lists True/False values by taking the cartesian product of the list [0, 1] with itself a number of times equal to the length of the input string. So each of the sublists has the same length as the input string. Then we apply the r function as a vector operation over the input and the list, so we get r letter value for each sub element. r with second argument zero is to lowercase and with one it is to upper case. This creates duplicates on non-letters, which means we need to remove duplicates from the result.

FryAmTheEggman

Posted 2016-05-31T13:17:26.517

Reputation: 16 206

@LeakyNun Ah, I had tried that but for some reason I thought using M on both s and .n was the same length. I seem to be good at counting. Anyway, editing now, thanks! – FryAmTheEggman – 2016-05-31T16:50:39.480

Yes they are the same length, I just changed the last part – Leaky Nun – 2016-05-31T23:41:19.140

{msrVQd^U2l is a little bit shorter. – Jakube – 2016-06-01T09:21:10.303

@Jakube Thanks! Using V is pretty sneaky, I don't think I would have ever thought of that here. – FryAmTheEggman – 2016-06-01T13:05:28.703

8

Jelly, 6 bytes

żŒsŒpQ

This is a monadic link (function) that expects a string as left argument and returns a list of strings.

Handles non-ASCII characters. Try it online!

How it works

żŒsŒpQ  Monadic link. Argument: s (string)

 Œs     Swapcase; change the case of all letters in s.
ż       Zipwith; pair each character with itself with changed case.
   Œp   Take the Cartesian product of all pairs.
     Q  Unique; deduplicate the Cartesian product.

Dennis

Posted 2016-05-31T13:17:26.517

Reputation: 196 637

3Get rekt other languages :p – Adnan – 2016-05-31T15:10:45.807

2Even after looking at the code-page, the fact that I consistently see Jelly with the lowest byte count on code-golf challenges amazes me. – Poke – 2016-05-31T15:30:46.280

5

Python, 74 71 bytes

f=lambda s:s and{r[0]+t for r in{s,s.swapcase()}for t in f(s[1:])}or{s}

Handles non-ASCII characters. Test it on Ideone.

Dennis

Posted 2016-05-31T13:17:26.517

Reputation: 196 637

5

Oracle SQL 11.2, 276 bytes

WITH v AS(SELECT SUBSTR(:1,LEVEL,1)c,ROWNUM p FROM DUAL CONNECT BY LEVEL<=LENGTH(:1))SELECT w FROM(SELECT REPLACE(SYS_CONNECT_BY_PATH(c,','),',','')w FROM(SELECT UPPER(c)c,p FROM v UNION SELECT LOWER(c),p FROM v)START WITH p=1CONNECT BY PRIOR p=p-1)WHERE LENGTH(:1)=LENGTH(w);

Un-golfed

WITH v AS
( -- Split input into an array of characters 
  SELECT SUBSTR(:1,LEVEL,1)c,ROWNUM p FROM DUAL CONNECT BY LEVEL<=LENGTH(:1)
)
SELECT w 
FROM   ( -- Build every string combination
         SELECT REPLACE(SYS_CONNECT_BY_PATH(c,','),',','')w 
         FROM   ( -- Merge upper and lower arrays, keep same position for each character, it allows to mix cases
                  SELECT UPPER(c)c,p FROM v UNION SELECT LOWER(c),p FROM v
                )
         START WITH p=1          -- Start with first character (either lowercase or uppercase)
         CONNECT BY PRIOR p=p-1  -- Add the next character (either lowercase or uppercase)
       )
WHERE LENGTH(:1)=LENGTH(w); -- Keep only full strings

Ugly as hell, must be more golfable.

Jeto

Posted 2016-05-31T13:17:26.517

Reputation: 1 601

4

05AB1E, 17 bytes

Code:

vyDš‚N0Êiâvy˜J})Ù

Explained:

vy                     # for each character in input
  Dš‚                  # create a pair of different case, eg: ['ž', 'Ž']
     N0Êiâ             # for all pairs but the first, take cartesian product
                         result will be a list of layered lists eg: [['ž', '1'], 'a'] 
            vy         # for each such list
              ˜J}      # deep flatten and join as a string eg: ž1a
                 )Ù    # wrap in array and remove duplicates

Try it online

Emigna

Posted 2016-05-31T13:17:26.517

Reputation: 50 798

4

Brachylog, 25 22 bytes

:ef:1fd.
:2ac.
@u.|@l.

This works as well as the lowercase/uppercase predicates of Prolog, therefore it works on non-ASCII letters too:

?- run("ž1a",Z).
Z = ["Ž1A", "Ž1a", "ž1A", "ž1a"] .

Explanation

Unlike all other answers as of the moment I'm posting this, this does not use the cartesian product approach at all.

  • Main Predicate

    :ef       Split the Input string into a list of 1-char strings
       :1f    Find all valid outputs of predicate 1 with the previous list
              of outputs as input
          d.  Unify the Output with that list excluding all duplicates
    
  • Predicate 1

This is used to apply uppercasing or lowercasing on each char of the input, thus computing one possible permutation. Using findall on this predicate in the main predicate allows to compute all possible permutations (with some duplicates).

    :2a       Apply predicate 2 on the each element of the Input
       c.     Unify the Output with the concatenation of the elements of
              the previous list
  • Predicate 2

This is used to turn a character of the string into either its uppercase or its lowercase version.

    @u.       Unify the Output with the uppercase version of the Input
       |      Or
        @l.   Unify the Output with the lowercase version of the input

Fatalize

Posted 2016-05-31T13:17:26.517

Reputation: 32 976

4

Haskell, 69 58 bytes

import Data.Char
mapM(\x->toLower x:[toUpper x|isAlpha x])

Try it online!

Edit: @Angs saved 11 bytes. Thanks!

nimi

Posted 2016-05-31T13:17:26.517

Reputation: 34 639

mapM(\x->toLower x:[toUpper x|isAlpha x]) should get rid of the other import? – Angs – 2018-05-01T20:16:44.957

3

MATL, 13 bytes

tYov!Z}N$Z*Xu

Try it online!

Explanation

t       % Implicit input string. Duplicate
Yo      % Change case of string
v       % Concatenate as a 2xN char array, where N is input length
!       % Transpose: Nx2 char array. Each row has different case, if letter
Z}      % Split into rows: gives N strings of 2 chars. Each char has different 
        % case if it's a letter, or is repeated otherwise
N$      % Specify N inputs for next function
Z*      % Cartesian product of the N strings. Each combination is a row.
        % Repeated chars (i.e. non-letters) give rise to duplicate rows.
Xu      % Remove duplicate rows. Implicit display

Luis Mendo

Posted 2016-05-31T13:17:26.517

Reputation: 87 464

3

JavaScript (Firefox 30-57), 92 90 bytes

f=([c,...s])=>c?[for(t of f(s))for(d of new Set(c.toUpperCase()+c.toLowerCase()))d+t]:['']

Edit: Saved 2 bytes because new Set will happily extract the unique characters from a string.

Neil

Posted 2016-05-31T13:17:26.517

Reputation: 95 035

When !c s is also [] so you can return [s] instead – l4m2 – 2017-12-27T14:32:18.133

f=([c,...s])=>c?[for(t of f(s))for(d of new Set(c.toUpperCase()+c.toLowerCase()))d+t]:[s] – l4m2 – 2018-05-03T05:45:45.480

3

Perl 6, 37 bytes

{[X~] '',|.comb.map:{unique .lc,.uc}}

Try it

Explanation:

{
  [X[~]]                     # cross combine using &infix:<~> operator
    '',                      # empty string so that 1 character strings work
    |                        # flatten the following into outer list
      .comb                  # get every character from input string
      .map:                  # and map it with:
        { unique .lc, .uc }
}

Test:

#! /usr/bin/env perl6

use v6.c;
use Test;

my &case-permutation = {[X~] '',|.comb.map: {unique .lc,.uc}}

my @tests = (
  'a1a' => <a1a a1A A1a A1A>,
  'abc' => <abc abC aBc aBC Abc AbC ABc ABC>,
  'Hi!' => <hi! hI! Hi! HI!>,
  'ž1a' => <ž1a ž1A Ž1a Ž1A>,
);

plan +@tests;

for @tests -> $_ (:key($input),:value($expected)) {
  is case-permutation($input).sort, $expected.sort, .gist
}
1..4
ok 1 - a1a => (a1a a1A A1a A1A)
ok 2 - abc => (abc abC aBc aBC Abc AbC ABc ABC)
ok 3 - Hi! => (hi! hI! Hi! HI!)
ok 4 - ž1a => (ž1a ž1A Ž1a Ž1A)

Brad Gilbert b2gills

Posted 2016-05-31T13:17:26.517

Reputation: 12 713

You can save a byte I think: {[X~] '',|.comb.map:{unique .lc,.uc}} (remove space after map:) – Conor O'Brien – 2018-05-02T14:19:38.853

2

C 229 252 bytes

i,n,j,k,l;f(char *s){l=strlen(s);for(i=0;i<l;i++)s[i]=tolower(s[i]);int v[l];for(i=0;i<l;i++)v[i]=0;for(i=0;i<pow(2,l);i++){n=i,k=0;for(;n;k++){v[k]=n;n/=2;}for(j=0;j<l;j++){v[j]%=2;if(v[j])s[j]=toupper(s[j]);else s[j]=tolower(s[j]);}printf("%s ",s);}}

Ungolfed version:

void f(char *s)
{
  int i,num,k,l=strlen(s);
  for(i=0;i<l;i++)
     s[i]=tolower(s[i]);

   int v[l];
   for(i=0;i<l;i++) 
     v[i]=0;   

   for(i=0;i<pow(2,l);i++)
   {
      num=i,k=0;
      for(;num;k++)
      {
         v[k]=num;
         num/=2;        
      } 

      for(int j=0;j<l;j++)
      {
        v[j]%=2;

        if(v[j])
         s[j]=toupper(s[j]);
        else
         s[j]=tolower(s[j]);

      }
      printf("%s \n",s);       

   } 
}

Explanation:

  • Accept the character string, convert the string to lowercase.
  • Declare integer array of length equal to that of the string. Fill it with zeroes.
  • Store the numbers from 0 to 2^strlen(s)in binary form in an int array.( For a 3 byte string: 000,001,010...111)
  • Depending on if a bit at a position is set or, toggle the case.
  • Output the string for every possible combination.

Try it online!

Abel Tom

Posted 2016-05-31T13:17:26.517

Reputation: 1 150

When I originally did this in vb6 like 10 years ago I believe my solution was similar to this one. You brought back some memories ;) – Poke – 2017-02-18T13:23:27.957

@Poke Glad that i could! :) – Abel Tom – 2017-02-18T16:47:22.553

Some things to golf: Remove the i++ in the for-loops and use ++ directly, as well as placing some parts inside the for-loop to remove brackets and semi-columns where possible. Also, you can remove the space in the parameter and use a ternary-if assignment at the end. In total: i,n,j,k,l;f(char*s){l=strlen(s);for(i=0;i<l;)s[i]=tolower(s[i++]);int v[l];for(i=0;i<l;)v[i++]=0;for(i=0;i<pow(2,l);){for(n=i++,k=0;n;n/=2)v[k++]=n;for(j=0;j<l;j++){v[j]%=2;s[j]=v[j]>0?toupper(s[j]):tolower(s[j]);}printf("%s ",s);}} (-20 bytes / 232 bytes) – Kevin Cruijssen – 2017-02-22T12:19:24.493

2

Julia, 66 60 bytes

!s=s>""?[~s[1:1]t for~=(ucfirst,lcfirst),t=!s[2:end]]∪[]:[s]

Try it online!

Dennis

Posted 2016-05-31T13:17:26.517

Reputation: 196 637

2

Python, 69 bytes

import itertools as i;f=lambda s:set(i.product(*zip(s,s.swapcase())))

RootTwo

Posted 2016-05-31T13:17:26.517

Reputation: 1 749

That returns tuples of singleton strings instead of strings. I'm not sure if that's allowed. – Dennis – 2016-06-01T05:50:29.863

Save 1 byte by using from itertools import*; and omitting the i. – Byte Commander – 2016-06-01T14:06:09.040

OP has said that singleton strings are not allowed. You should update this answer. – James – 2016-06-01T19:36:32.083

The output requirement is ambiguous (still is). After I posted this, the OP clarified in the comments. Should I just delete this answer? What is the proper protocol? – RootTwo – 2016-06-02T04:23:50.017

2

Actually, 28 bytes

;╗l2r∙`"'Ö*£"£M╜@Z"iƒ"£MΣ`M╔

Try it online!

This program can handle non-ASCII characters, thanks to the magic of Python 3.

Explanation:

;╗l2r∙`"'Ö*£"£M╜@Z"iƒ"£MΣ`M╔
;╗                            save a copy of input to reg0
  l                           length of input
   2r                         [0,1]
     ∙                        Cartesian product with self (length of input) times
      `                  `M   map:
       "'Ö*£"£M                 push `Ö` (swapcase) if 1 else `` for each value in list
               ╜@Z              zip with input
                  "iƒ"£M        swap the case of those values
                        Σ       join string
                           ╔  unique elements

Mego

Posted 2016-05-31T13:17:26.517

Reputation: 32 998

1

C, 216 bytes

k,i,j,p,n,m;z(char *c){n=-1;m=0;while(c[++n])if(c[n]>64&c[n]<90)c[n]+=32;else if(c[n]<'a'|c[n]>'z')m++;k=1<<(n-m);for(j=0;j<k;j++){for(i=0;i<n;i++){p=1<<i;putc((j&p)==p?toupper(c[i]):c[i],stdout);}putc(0xa,stdout);}}

This is a different approach, the same approach as the other C answer.

Should I delete this, and put it under the other answer as a comment?

Let me explain with the Ungolfed version

k,i,j,p,n,m;
z(char * c) {
    int n=-1;       // We start at -1 because of forward incrementation
    int m=0;        // this will count the characters we don't have to manipulate
    while(c[++n])   // go until we reach '\0'
    {
        if(c[n]>='a'&c[n]<='z')c[n]-=32; // If we are lower case, then convert
        else if(c[n]<'A'|c[n]>'Z')m++;   // If we are neigther lower case
                                         // nor upper, then make a note
    }

    // get 2 ^ ("length" - "number of invonvertibles")
    k=1<<(n-m); 
    for(j=0;j<k;j++) {      // go through the combinations
        for(i=0;i<n;i++) {  // for each combination go though the characters
            p=1<<i;         // for each character get it's bit position
            putc(
                // if the bit position is set (==1) 
                (j&p)==p ?
                   tolower(c[i]) // convert
                   : c[i], // else: don't
                stdout);
        }
        putc(0xa, stdout);  // print a newline
    }
}

MrPaulch

Posted 2016-05-31T13:17:26.517

Reputation: 771

1

Python3, 96 bytes

i=input().lower()
for l in{*__import__('itertools').product(*zip(i,i.upper()))}:print(*l,sep='')

Late to the party but still had a go. Thanks to DLosc for reminding me of the stuff I missed, giving me golfing tips and saving me a bunch of bytes. :)

Blocks

Posted 2016-05-31T13:17:26.517

Reputation: 141

@DLosc Thanks for the tips! I'll add those features in. :) – Blocks – 2017-02-22T07:16:01.020

Thanks for the tips. It really helped. Although if I use {} instead of set(), the loop goes through the set instead of the products (I hope that makes sense). At least on my implementation (I'm using QPython on Android), {} just puts the list inside a set instead of converting the list to a set. – Blocks – 2017-02-22T11:00:31.667

I've tried both ways and doing {*expr} gives me a SyntaxError. – Blocks – 2017-02-23T05:58:11.163

Ahhhh. That's why. Latest version of QPython is on 3.3 or something. – Blocks – 2017-02-23T07:09:45.847

Here you go: Try it online! (Also fixed a bug and golfed a space.)

– DLosc – 2017-02-23T07:17:33.770

1

Wolfram Language (Mathematica), 55 bytes

""<>#&/@Union@Tuples[{#,ToUpperCase@#}]&@*Characters

Try it online!

is the transpose operator (and displays as a superscript T in Mathematica).

Martin Ender

Posted 2016-05-31T13:17:26.517

Reputation: 184 808

1

Perl 5, 52 + 1 (-n) = 53 bytes

@k{glob s/./lc("{$&,").uc"$&}"/ger}++;say for keys%k

Try it online!

Xcali

Posted 2016-05-31T13:17:26.517

Reputation: 7 671

1

Perl 5, 30 bytes

s/\pl/{\l$&,\u$&}/g;say<"$_ ">

Try it online!

Outputs an additional space at the end of the output.

Dom Hastings

Posted 2016-05-31T13:17:26.517

Reputation: 16 415

1

Attache, 39 bytes

&Cross[Sum@V]##Unique@V#SwapCase=>Chars

Try it online!

Similar to the perl answer. (I've lost my more interesting alternative, I should be posting those in the next few hours.)

Conor O'Brien

Posted 2016-05-31T13:17:26.517

Reputation: 36 228

1

Hoon, 242 bytes

|=
t/tape
=+
l=(reap (pow 2 (lent t)) t)
%+
roll
(gulf 0 (dec (lent l)))
|=
{a/@ b/(set tape)}
=+
%+
turn
(gulf 0 (dec (lent t)))
|=
n/@
=+
t=(snag n t)
=+
k=(trip t)
?:
=(0 (cut 0 n^1 a))
?:
=((cuss k) t)
(cass k)
(cuss k)
t
(~(put in b) -)

Ungolfed:

|=  t/tape
=+  l=(reap (pow 2 (lent t)) t)
%+  roll  (gulf 0 (dec (lent l)))
|=  {a/@ b/(set tape)}
    =+  %+  turn  (gulf 0 (dec (lent t)))
      |=  n/@
      =+  t=(snag n t)
      =+  k=(trip t)
      ?:  =(0 (cut 0 n^1 a))
        ?:  =((cuss k) t)
              (cass k)
        (cuss k)
      t
    (~(put in b) -)

I'm not sure how much smaller this could be, unfortunately.

First, we set l equal to a list with 2^(length t) repetitions of t. Hoon doesn't have a fac function in the stdlib, but 2^n is always bigger than n!, so we simply map over the bigger list and use a set (hashmap) to de-duplicate entries.

We then fold over the list [0..(length l)], accumulating into a (set tape). We need to do this instead of mapping over l directly because we also need to know what number repetition it is (a), but can't simply increment an accumulator due to Hoon being a pure language.

We map over [0..(length t)] (again so we have the current index), setting t to the nth character in the string, checking if the nth bye of a and inverting the case (cuss or cass, depending if it changes or not). The return type of this map is a tape.

We then put the string into our hashmap, and return the hashmap of all the strings.

RenderSettings

Posted 2016-05-31T13:17:26.517

Reputation: 620

"2^n is always bigger than n!". Actually n! > 2^n, provided that n is at least 4. (Prove by induction, with base case n=4.) https://en.wikipedia.org/wiki/Factorial#Rate_of_growth_and_approximations_for_large_n

– mathmandan – 2016-06-04T14:26:20.790

1

Tcl, 165 181 bytes

set n -1
while {[incr n]<1<<[llength [set s [split $argv {}]]]} {puts [join [lmap c $s b [split [format %0[llength $s]b $n] {}] {string to[expr $b?{u}:{l}] $c}] ""]}

Improvements thanks to sergiol. Previous answer:

set s [split $argv {}]
set n -1
while {[incr n]<1<<[llength $s]} {set r ""
foreach c $s b [split [format %0[llength $s]b $n] {}] {set r $r[string [expr $b?{tou}:{tol}] $c]}
puts $r}

Uses a binary number to choose between upper/lower case when creating the output text.

Dúthomhas

Posted 2016-05-31T13:17:26.517

Reputation: 541

165 – sergiol – 2018-04-28T21:42:23.033

@sergiol That's different enough from mine that you ought to post it as your own answer and get good cred for being awesome. – Dúthomhas – 2018-04-29T21:08:52.893

No. I only changed minor parts of your answer, I did not change the approach nor the essential algorithmics, so, in my point of view I thought I did not deserve to create a new answer out form yours! And I doubt I could get an algorithm short as your original for the same purpose! – sergiol – 2018-04-29T21:45:32.860

0

JavaScript (ES6), 103

Handles non-ASCII characters

(a,r=new Set)=>a?f(a.slice(1)).map(v=>(C=o=>r.add(a[0][`to${o}erCase`]()+v),C`Upp`,C`Low`))&&[...r]:[a]

Test

f=(a,r=new Set)=>a?f(a.slice(1)).map(v=>(C=o=>r.add(a[0][`to${o}erCase`]()+v),C`Upp`,C`Low`))&&[...r]:[a]

function test() { O.textContent = f(I.value).join('\n') }

test()
<input id=I oninput='test()' value='ž1a'>
<pre id=O></pre>

edc65

Posted 2016-05-31T13:17:26.517

Reputation: 31 086