17
\$\begingroup\$

Given a key, and an array of strings, shuffle the array so that it is sorted when each element is XOR'd with the key.

XOR'ing two strings

To XOR a string by a key, XOR each of the character values of the string by its pair in the key, assuming that the key repeats forever. For example, abcde^123 looks like:

       a        b        c        d        e
       1        2        3        1        2
--------------------------------------------
01100001 01100010 01100011 01100100 01100101
00110001 00110010 00110011 00110001 00110010
--------------------------------------------
01010000 01010000 01010000 01010101 01010111
--------------------------------------------
       P        P        P        U        W

Sorting

Sorting should always be done Lexicographically of the XOR'd strings. That is, 1 < A < a < ~ (Assuming ASCII encoding)

Example

"912", ["abcde", "hello", "test", "honk"]

-- XOR'd
["XSQ]T", "QT^U^", "MTAM", "Q^\R"]
-- Sorted
["MTAM", "QT^U^", "Q^\R", "XSQ]T"]
-- Converted back
["test", "hello", "honk", "abcde"]

Notes

  • Key will always be at least 1 character
  • Key and Input will only consist of printable ASCII.
  • XOR'd strings may contain non-printable characters.
  • Input and Output may be done through the Reasonable Methods
  • Standard Loopholes are forbidden.
  • You may take Key and Input in any order.

Test Cases

key, input -> output
--------------------
"912", ["abcde", "hello", "test", "honk"] -> ["test", "hello", "honk", "abcde"]
"taco", ["this", "is", "a", "taco", "test"] -> ["taco", "test", "this", "a", "is"]
"thisisalongkey", ["who", "what", "when"] -> ["who", "what", "when"]
"3", ["who", "what", "when"] -> ["what", "when", "who"]

This is , so least bytes wins!

\$\endgroup\$
5
  • \$\begingroup\$ Related nowhere near a dupe though \$\endgroup\$
    – MD XF
    Dec 28, 2017 at 3:51
  • \$\begingroup\$ Are the strings guaranteed to be different? \$\endgroup\$
    – Neil
    Dec 28, 2017 at 10:00
  • \$\begingroup\$ @Neil Although I can't imagine a situation where them being identical would cause problems, you can assume that all strings will be unique. \$\endgroup\$
    – ATaco
    Dec 28, 2017 at 10:07
  • \$\begingroup\$ @ATaco It can certainly matter if you're not using built-in string comparison. \$\endgroup\$
    – Dennis
    Dec 28, 2017 at 19:00
  • \$\begingroup\$ Should have been called "XORt an array" :p \$\endgroup\$
    – lyxal
    Aug 31, 2023 at 13:12

17 Answers 17

10
\$\begingroup\$

Python 3, 75 73 bytes

lambda k,x:x.sort(key=lambda s:[ord(x)^ord(y)for x,y in zip(s,k*len(s))])

This sorts the list x in-place.

Thanks to @mercator for golfing off 2 bytes!

Try it online!

Alternate version, 62 bytes

This takes input as byte strings, which may not be allowed.

lambda k,x:x.sort(key=lambda s:[*map(int.__xor__,s,k*len(s))])

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ In-place sorting saves 2 bytes: x.sort(key=...). \$\endgroup\$
    – mercator
    Dec 28, 2017 at 19:02
7
\$\begingroup\$

Jelly, 9 7 bytes

⁹ṁO^OµÞ

Thanks to @EriktheOutgolfer for a suggestion that helped saving 2 bytes!

Try it online!

How it works

⁹ṁO^OµÞ  Dyadic link.
         Left argument: A (string array). Right argument: k (key string).

     µ   Combine the code to the left into a chain.
         Begin a new, monadic chain with argument A.
      Þ  Sort A, using the chain to the left as key.
         Since this chain is monadic, the key chain will be called monadically,
         once for each string s in A.
⁹            Set the return value to the right argument of the link (k).
 ṁ           Mold k like s, i.e., repeat its characters as many times as necessary
             to match the length of s.
  O          Ordinal; cast characters in the resulting string to their code points.
    O        Do the same for the chain's argument (s).
   ^         Perform bitwise XOR.
\$\endgroup\$
0
3
\$\begingroup\$

Ruby, 61 bytes

->k,w{w.sort_by{|x|x.bytes.zip(k.bytes.cycle).map{|x,y|x^y}}}

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Haskell, 77 bytes

import Data.Bits
import Data.List
t=fromEnum
sortOn.zipWith((.t).xor.t).cycle

Too many imports.

Try it online!

\$\endgroup\$
3
\$\begingroup\$

x86 opcode, 57 Bytes

0100  60 89 CD 4D 8B 74 8A FC-8B 3C AA 53 F6 03 FF 75
0110  02 5B 53 8A 23 AC 08 C0-74 0A 30 E0 32 27 47 43
0120  38 E0 74 E8 77 0A 8B 04-AA 87 44 8A FC 89 04 AA
0130  85 ED 5B 75 CE E2 CA 61-C3

    ;input ecx(length), edx(array), ebx(xor-d)
F:  pushad
L1: mov ebp, ecx
L2: dec ebp
    mov esi, [edx+ecx*4-4]
    mov edi, [edx+ebp*4]
    push ebx
L6: test [ebx], byte -1 ; t1b
    jnz L4
    pop ebx
    push ebx
L4: mov ah, [ebx]
    lodsb
    or  al, al
    jz  L7
    xor al, ah
    xor ah, [edi]
    inc edi
    inc ebx
    cmp al, ah
    jz  L6
L7: ja  L8
    mov eax, dword[edx+ebp*4]
    xchg eax, dword[edx+ecx*4-4]
    mov dword[edx+ebp*4], eax
L8: ;call debug
    test ebp, ebp
    pop ebx
    jnz L2
    loop L1
    popad
    ret            

Test code:

if 1
    use32
else
    org $0100
    mov ecx, (Qn-Q0)/4
    mov edx, Q0
    mov ebx, S
    call F
    call debug
    ret

debug:pushad
    mov ecx, (Qn-Q0)/4
    mov edx, Q0
    mov ebx, S
E3:   mov esi, [edx]
    push dx
    mov ah, 2
E4:   lodsb
    cmp al, 0
    jz E5
    mov dl, al
    int $21
    jmp E4
E5:   mov dl, $0A
    int $21
    mov dl, $0D
    int $21
    pop dx
    add edx, 4
    loop E3
    ;mov ah, 1
    ;int $21
    int1
    popad
    ret
    align 128
Q0:
    dd str1, str2, str3, str4
Qn:
S     db '912', 0
str1  db 'abcde', 0
str2  db 'hello', 0
str3  db 'test', 0
str4  db 'honk', 0
    align 128
end if
    ;input ecx(length), edx(array), ebx(xor-d)
F:  pushad
L1: mov ebp, ecx
L2: dec ebp
    mov esi, [edx+ecx*4-4]
    mov edi, [edx+ebp*4]
    push ebx
L6: test [ebx], byte -1 ; t1b
    jnz L4
    pop ebx
    push ebx
L4: mov ah, [ebx]
    lodsb
    or  al, al
    jz  L7
    xor al, ah
    xor ah, [edi]
    inc edi
    inc ebx
    cmp al, ah
    jz  L6
L7: ja  L8
    mov eax, dword[edx+ebp*4]
    xchg eax, dword[edx+ecx*4-4]
    mov dword[edx+ebp*4], eax
L8: ;call debug
    test ebp, ebp
    pop ebx
    jnz L2
    loop L1
    popad
    ret
\$\endgroup\$
2
\$\begingroup\$

Clean, 101 100 94 bytes

-6 bytes thanks to Ourous!

import StdEnv
? =toInt
s k=let%s=[b bitxor?a\\a<-s&b<-[?c\\_<-s,c<-k]];@a b= %b> %a in sortBy@

Try it online! Example usage: s ['3'] [['who'], ['what'], ['when']].

Ungolfed:

import StdEnv
sort key list = 
   let
      f string = [(toInt a) bitxor (toInt b) \\ a<-string & b<-flatten(repeat key)]
      comp a b = f a <= f b
   in sortBy comp list
\$\endgroup\$
2
  • \$\begingroup\$ ? =toInt and using ? instead saves 2 bytes, and using a flipped greater-than instead of less-or-equals saves another one. \$\endgroup\$
    – Οurous
    Dec 28, 2017 at 19:59
  • \$\begingroup\$ Even better, saves 6 bytes: TIO \$\endgroup\$
    – Οurous
    Dec 29, 2017 at 0:38
2
\$\begingroup\$

JavaScript ES 6, 113 97 95 Bytes

k=>p=>p.sort((a,b,F=x=>[...x].map((y,i)=>1e9|y.charCodeAt()^(p=k+p).charCodeAt(i)))=>F(a)>F(b))

JavaScript is long at charcoding...

For [0,65536) +1e4 all be 5 digits so can be compared like string

Q=
k=>p=>p.sort((a,b,F=x=>[...x].map((y,i)=>1e9|y.charCodeAt()^(p=k+p).charCodeAt(i)))=>F(a)>F(b))
;
console.log(Q("912")(["abcde", "hello", "test", "honk"]));
console.log(Q("taco")(["this", "is", "a", "taco", "test"]));
console.log(Q("thisisalongkey")(["who", "what", "when"]));
console.log(Q("3")(["who", "what", "when"]));

\$\endgroup\$
1
  • \$\begingroup\$ Threoiy I can use k+=k instead of p=k+p but too many memory using with the small test case \$\endgroup\$
    – l4m2
    Dec 28, 2017 at 4:25
1
\$\begingroup\$

Actually, 24 bytes

O╗⌠;O;l;╜@αH♀^♂cΣ@k⌡MS♂N

Try it online!

Explanation:

O╗⌠;O;l;╜@αH♀^♂cΣ@k⌡MS♂N
O╗                        store ordinals of key in register 0
  ⌠;O;l;╜@αH♀^♂cΣ@k⌡M     for each string in array:
   ;O                       make a copy, ordinals
     ;l;                    make a copy of ordinals, length, copy length
        ╜@αH                list from register 0, cycled to length of string
            ♀^              pairwise XOR
              ♂cΣ           convert from ordinals and concatenate
                 @k         swap and nest (output: [[a XOR key, a] for a in array])
                     S♂N  sort, take last element (original string)
\$\endgroup\$
2
  • \$\begingroup\$ @ATaco No it doesn't. Try it with ["who", "what", "when"] and "thisisalongkey" \$\endgroup\$ Dec 28, 2017 at 7:57
  • 1
    \$\begingroup\$ @cairdcoinheringaahing That was posted before a patch to Actually on TIO. \$\endgroup\$
    – ATaco
    Dec 28, 2017 at 8:55
1
\$\begingroup\$

Perl 6, 37 bytes

{@^b.sort(*.comb Z~^(|$^a.comb xx*))}

Try it online!

$^a and @^b are the key and array arguments to the function, respectively. @^b.sort(...) simply sorts the input array according to the predicate function it is given. That function takes a single argument, so sort will pass it each element in turn and treat the return value as a key for that element, sorting the list by the keys of the elements.

The sorting function is *.comb Z~^ (|$^a.comb xx *). * is the single string argument to the function. *.comb is a list of the individual characters of the string. |$^a.comb xx * is a list of the characters in the xor sorting key, replicated infinitely. Those two lists are zipped together (Z) using the stringwise xor operator (~^). Since the sorting predicate returns a sort key which is a list, sort orders two elements by comparing the first elements of the returned lists, then the second elements if the first elements are the same, et cetera.

\$\endgroup\$
1
  • \$\begingroup\$ {sort *.comb »~^»$^a.comb,@^b} \$\endgroup\$ Dec 29, 2017 at 3:52
1
\$\begingroup\$

C (gcc), 132 128 126 bytes

char*k;g(a,b,i,r)char**a,**b;{r=k[i%strlen(k)];(r^(i[*a]?:-1))-(r^(i[*b]?:-2))?:g(a,b,i+1);}f(c,v)int*v;{k=*v;qsort(v,c,8,g);}

Takes an argument count and a pointer to a string array (the key, followed by the strings to be sorted) and modifies the string array in-place.

The code is highly non-portable and requires 64-bit pointers, gcc, and glibc.

Thanks to @ceilingcat for golfing off 2 bytes!

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

Python 2,  204 140 134  126 bytes

Thanks to @Mr. Xcoder for saving 64 bytes, thanks to @ovs for saving six bytes, and thanks to @Dennis for saving eight bytes!

lambda k,l:[x(k,s)for s in sorted(x(k,s)for s in l)]
x=lambda k,s:''.join(chr(ord(v)^ord(k[i%len(k)]))for i,v in enumerate(s))

Try it online!

\$\endgroup\$
0
0
\$\begingroup\$

Perl 5, 88 bytes

sub{[map@$_[0],sort{@$a[1]cmp@$b[1]}map[$_,substr$_^($_[0]x length),0,length],@{$_[1]}]}

Try it online.

\$\endgroup\$
0
\$\begingroup\$

Clojure, 80 bytes

#(sort-by(fn[s](apply str(apply map bit-xor(for[i[(cycle %)s]](map int i)))))%2)
\$\endgroup\$
0
\$\begingroup\$

Perl 5, 80 + 3 (anl) = 83, 67 bytes

sub{$,=shift;sub X{$_^substr$,x y///c,0,y///c};map X,sort map X,@_}

try it online

\$\endgroup\$
3
  • \$\begingroup\$ This repeats the key 9 times, which isn’t enough in general. For example, the output will be wrong for 9; abcdeabcde abcdeabcdz (should give abcdeabcdz abcdeabcde) \$\endgroup\$
    – Lynn
    Dec 28, 2017 at 12:40
  • \$\begingroup\$ @Lynn, fixed adding 3 bytes \$\endgroup\$ Dec 28, 2017 at 13:43
  • \$\begingroup\$ could save 16 bytes using subs \$\endgroup\$ Dec 28, 2017 at 14:06
0
\$\begingroup\$

AWK, 285 284 bytes

{for(;z++<128;){o[sprintf("%c",z)]=z}split(substr($0,0,index($0,FS)),k,"");$1="";split($0,w);for(q in w){split(w[q],l,"");d="";for(;i++<length(l);){d=d sprintf("%c",xor(o[k[(i-1)%(length(k)-1)+1]],o[l[i]]))}a[q]=d;i=0}asort(a,b);for(j in b){for(i in a){printf(a[i]==b[j])?w[i]FS:""}}}

Try it online!

Accepts input in the form of key word word ... eg 912 abcde hello test honk

Outputs sorted words space separated

Slightly more readable

{
  for (; z++ < 128;) {
    o[sprintf("%c", z)] = z
  }
  split(substr($0, 0, index($0, FS)), k, "");
  $1 = "";
  split($0, w);
  for (q in w) {
    split(w[q], l, "");
    d = "";
    for (; i++ < length(l);) {
      d = d sprintf("%c", xor(o[k[(i - 1) % (length(k) - 1) + 1]], o[l[i]]))
    }
    a[q] = d;
    i = 0;
  }
  asort(a, b);
  for (j in b) {
    for (i in a) {
      printf(a[i] == b[j]) ? w[i] FS : ""
    }
  }
}  
\$\endgroup\$
0
\$\begingroup\$

Factor, 85

[ [ dup length rot <array> concat [ bitxor ] 2map ] with
[ dup bi* <=> ] curry sort ]

First try, I'll see if I can golf it further tomorrow.

I accept suggestions ;)

\$\endgroup\$
0
\$\begingroup\$

Dyalog APL, 34 bytes

Dfn, uses ⎕ml 3

{⍵[⍋⊃82⎕dr¨⊃≠/11⎕dr¨¨⍵((⍴¨⍵)⍴⊂⍺)]}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.