# Three other numbers

Given three distinct numbers from $$\1\$$ to $$\7\$$, output three other distinct numbers from $$\1\$$ to $$\7\$$, that is having no numbers in common with the original numbers. Your code must produce a different output set for each possible input set. That is, no two inputs can produce the same output, treating both as unordered sets. Other than that, you can implement whatever mapping you want.

More mathematically, you're asked to give a bijection (one-to-one function) $$\f:S \to S\$$ where $$\S\$$ consists of three-element subsets of $$\\{1,2,3,4,5,6,7\}\$$, such that $$\f(s) \cap s = \emptyset\$$ for every $$\s\in S\$$. As a bijection, this mapping has to be invertible, though you don't have to provide the inverse function in your code.

I/O

The format of the three-element sets is flexible. You can take the inputs in sorted order as three numbers or a three-element list/array/tuple, or as a set. You may not, however, require ordered inputs in a specific order other than sorted. You may zero index.

You may also use a sequence of seven bits of which three are on. This seven-bit sequence can also be represented as as a decimal number, byte, or character.

Output can be given in any of these formats, with the further allowance that ordered outputs don't have to be sorted.

• Either this is trickier than it looks or I'm drunker than I think! – Shaggy Oct 9 '20 at 20:41
• May we take input (or output) from $0$ to $6$ instead? – att Oct 9 '20 at 21:31
• Is it reasonable to return the single number not included in either of the two sets? – att Oct 9 '20 at 21:35
• @att No, you need to return the set. – xnor Oct 9 '20 at 21:48

# Python 3, 53 bytes

def f(b):c=[*{*range(7)}-b];del c[-sum(b)%4];return c


Try it online!

-3 bytes thanks to FryAmTheEggman
-4 bytes by zero-indexing
-1 byte thanks to xnor

• @xnor Honestly, I just brute forced all numbers x,y,z in the range [0,10) and found the ones where b[0]*x + b[1]*y + b[2]*z would not result in any collisions, and found x=y=z=3 and x=y=z=7 as the two options that would be golfiest. In other words, I have absolutely no proof and just did trial and error until I found one :P – HyperNeutrino Oct 9 '20 at 20:28
• Well, there's something weird and impressive going on here. This same thing doesn't seem to hold for parameters other than 7 and 3. It seems to hinge on the following result: Inside any four-element $T$ of $S$, there is exactly one element $x \in T$ such that the number of elements of $S-T$ that are less than $x$ is equal modulo 4 to $x - \mathrm{sum}(T)$. – xnor Oct 9 '20 at 20:36
• I think I figured out why it's a bijection and have a proof. It turns out that the inverse map is the same code except you replace -sum(b) with (1-sum(b)): Try it online!. Here, the 1 is the sum of {0,1,2,3,4,5,6} modulo 4. – xnor Oct 9 '20 at 22:28
• Amazing... I discovered the same when constructing my Jelly solution AND I started with sum * 3 and golfed to -sum. – Jonathan Allan Oct 9 '20 at 22:50
• One speculative explanation for the parameters 7 and 3 is that the smallest finite projective plane has seven points/lines, and every line contains three points/every point lies on three lines. For the next smallest projective plane, 7 and 3 are replaced by 13 and 4, respectively; I wonder whether there's anything to trying this same algorithm with those parameters. – Greg Martin Oct 12 '20 at 0:38

# Python 3, 43 bytes

lambda s:([*{*range(7)}-s]*4)[-sum(s):][:3]


Try it online!

• Ooh, repeating the list to avoid modulus on rotations is smart. Can't believe I didn't remember that; must have been too long since I've done this sort of stuff – HyperNeutrino Oct 9 '20 at 22:44

# Jelly,  9 8  7 bytes

7RṚḟṙSḊ


A monadic Link accepting a list of the three numbers, from $$\[1,7]\$$, in sorted order which yields a list of other numbers, from $$\[1,7]\$$, not necessarily sorted.

Try it online! Or see all 35 (I sorted the resulting values for easier comparison).

### How?

7RṚḟṙSḊ - Link: list A                   e.g.  [2,4,7]
7R      - seven range                          [1,2,3,4,5,6,7]
Ṛ     - reverse                              [7,6,5,4,3,2,1]
ḟ    - filter discard (A) -> B              [6,5,3,1]
S  - sum (A)                              13
ṙ   - rotate (B) left by (that)            [5,3,1,6]
Ḋ - remove the leftmost                  [3,1,6]

• Do you actually need N$? Isn't it just-as-effective to rotate left as to rotate right? – Dominic van Essen Oct 11 '20 at 12:13 • @DominicvanEssen there is no rotate right atom, but I can reverse the list prior to filtering and dequeue at the end rather than pop which saves a byte. – Jonathan Allan Oct 11 '20 at 13:03 • What I meant was, if you leave-out N$ you're effectively rotating left (since you're rotating by a positive number now), and it seems to be Ok, I think: 6 bytes... or am I missing something obvious...? – Dominic van Essen Oct 11 '20 at 13:26
• @DominicvanEssen that produces repeats (e.g 123 and 135 give the same output) – Jonathan Allan Oct 11 '20 at 14:18
• Yes. Sorry. I thought I'd looked, but apparently not very carefully. – Dominic van Essen Oct 11 '20 at 14:26

# R, 33 31 bytes

Edit: -2 bytes by using modulo -4 (which returns the negative of modulo 4)

(1:7)[v<--scan()][sum(v)%%-4-1]


Try it online!

Finds the 4 digits in 1..7 that aren't in the input, and excludes the one corresponding to the input sum (wrapping around).

TIO link tests that outputs are unique for each input, and shows output for every input.

(1:7)                   # vector of digits 1..7
[          ]       # select elements
-scan()        # excluding (negative indexes) input
v<-               # and define v as (negative) input
# (so up to here we have the 4 elements that aren't in the input)
[              ]   # from these, select elements
-                 # excluding (negative index)
(sum(v)%%4+1)    # the sum of input, modulo 4, plus 1

• Very nice! The exclusion rule is clever. – Cong Chen Oct 10 '20 at 13:05

# Japt, 14 bytes

As previously advertised, I'm a wee bit tipsy so this could well be wrong and, even if right, could probably be golfed a little.

7õ kU kÏ¶UxÍu4


# Charcoal, 393834 32 bytes

ＮθＩ⁻¹²⁷⁺θＸ²⊟Φ⁷№ＥTXdhp﹪×℅λＸ²ι¹²⁷θ


Try it online! Link is to verbose version of code. I/O is as a 7-bit integer 7..112. Explanation: The ordinals of the string TXdhp have five bit patterns which I have arbitrarily chosen to be such that the result excludes 1. They are then cyclically rotated until one matches the input, at which point I have determined the excluded bit. This bit is then added to the original input, and finally the difference between 127 and the sum is printed.

Ｎθ                                  Cast input to integer
⁷                      Literal 7
Φ                       Filter on implicit range
TXdhp               Literal string TXdhp
Ｅ                    Map over characters
λ           Current character
℅            Ordinal
×             Multiplied by
²         Literal 2
Ｘ          Raised to power
ι        Outer index
﹪              Modulo
¹²⁷     Literal 127
№                     Count (i.e. contains)
θ    Input
⊟                        Pop matching value
²                         Literal 2
Ｘ                          Raised to that power
θ                           Input
⁻                                Subtracted from
¹²⁷                             Literal 127
Ｉ                                 Cast to string
Implicitly print


I arbitrarily chose the following five bit patterns to exclude 1 but any five even cyclically distinct patterns would work.

T   1010100
X   1011000
d   1100100
h   1101000
p   1110000


# JavaScript (ES6),  66  65 bytes

Takes input as a 3-digit string. Returns a string in the same format.

f=(n,k=i=0)=>++k<8?(~n.search(k)||n*43%399%4==i++?'':k)+f(n,k):''


Try it online!

# 05AB1E, 10 bytes

7LsKsO(._¨


Try it online!

### How?

7LsKsO(._¨ - (push the input)      e.g.: [2,4,7]
7          - push 7                      7,[2,4,7]
L         - range                       [1,2,3,4,5,6,7],[2,4,7]
s        - swap top two of the stack   [2,4,7],[1,2,3,4,5,6,7]
K       - push a without bs           [1,3,5,6]
s      - swap top two of the stack   [2,4,7],[1,3,5,6]  (implicit input swapped in)
O     - sum                         13,[1,3,5,6]
(    - negate                      -13,[1,3,5,6]
._  - rotate a left by b          [6,1,3,5]
¨ - remove rightmost            [6,1,3]
- implicit print top of stack [6,1,3]


# C (gcc), 84 83 bytes

Saved a whopping 16 19 23 bytes thanks to the man himself ceilingcat!!!
Saved a byte thanks to Neil!!!

p;i;f(m){for(p=i=0;(L"᰸ᨴᘬᤲᔪ"[p]>>i%7&m)-m;p+=++i%7<1);p=(64>>i%7)+m^127;}


Try it online!

Takes input as $$\3\$$ bits set in the least-significant-$$\7\$$-bits of an int and returns the three other numbers likewise.

### Explanation (before some golfs)

f(m){                                  // function taking an integer with
// 3 bits set in its 7 lsb
// representing the 3 input numbers
for(                              // loop over
p=L"ᔪᘬᤲᨴ᰸"                     // a sequence of 5 int values:
//   5418,5676,6450,6708,7224
// that are the 5 unique patterns of
// 3 set bits per 7 bits shifted and
// repeated over 13 bits so that their
// 7th bit is unset:
//   5418 = 1010100101010
//   5676 = 1011000101100
//   6450 = 1100100110010
//   6708 = 1101000110100
//   7224 = 1110000111000
;;++p)             // no need to test for stopping
// since we must match one
for(i=7;i--;)                   // loop over shift values from 6 to 0
if((*p>>6-i&m)==m)            // if a shifted 7-bit slice of one of
// our patterns matches m we've found
// the correct bit to exclude from m's
// 4 unset bits
return(1<<i)+m^127;        // add that bit to m and flip the 7
// lsb so the 3 other unset bits are
// now set to represent the 3 return
// values
}

• Save 1 byte by using p>>i and 64>>i. – Neil Oct 18 '20 at 18:49
• @Neil Nice one - thanks! :-) – Noodle9 Oct 18 '20 at 21:38

# Husk, 9 bytes

hṙ_Σ¹-ḣ7


Try it online!

• This is really nice. I just tried before looking at this, and ended-up with Ṡfo≠→%4Σ⁰€fo¬€⁰ḣ7... 17 bytes, which now seems ridiculous looking at your 9 bytes! Well done. – Dominic van Essen Oct 10 '20 at 13:08
• Ah! - = list difference. I knew there should be something like that hiding among the commands... but didn't find it! – Dominic van Essen Oct 10 '20 at 13:12
• @DominicvanEssen want an explanation? – Razetime Oct 10 '20 at 13:27
• I've worked-through it myself by now (and learned a lot), but anyway I do think it's nice to generally include an explanation, especially while Husk is language of the month... – Dominic van Essen Oct 10 '20 at 13:39

# Perl 5, 49 bytes

sub{@c=grep!/[@_]/,0..6;splice@c,-sum(@_)%4,1;@c}


Try it online!

Just a translation of the python answer from HyperNeutrino.

# Scala, 64 bytes

b=>1.to(7).diff(b).zipWithIndex.filter(_._2!=b.sum*3%4)map(_._1)


Try it online!

• Welcome to Code Golf, then! I'm very happy to see someone else using Scala :) – user Oct 12 '20 at 15:14

# Ruby, 38 bytes

->s{n=s.sum;(([*1..7]-s)*9)[-n..-n+2]}


Try it online!

Stealing Eric's answer which based on Jonathan's answer. I would've commented to Eric, but i do not have enough reputation.

The actual difference: Using a range to get the three elemented slice.

• Nice first answer! – Redwolf Programs Oct 12 '20 at 17:49

# Ruby, 40 bytes

->s{(([*1..7]-s)*9).last(s.sum).first 3}


Try it online!

Ruby port of Jonathan's answer.

# 05AB1E, 17 bytes

7LIм{3.\$IO(._Dg<£


Try it online!

It's a much longer version of the Jelly answer, so go upvote that too.

# APL+WIN, 20 bytes

Prompts for input of a vector of integers

3↑(-+/¯2↑n)⌽n←(⍳7)~⎕


Try it online! Thanks to Dyalog Classic

• @Ven Thanks but I am afraid my ancient APL+WIN interpreter does not support trains. – Graham Oct 12 '20 at 14:20

# APL (Dyalog Unicode), 13 bytesSBCS

1∘↓+/⌽(⌽⍳7)∘~


Try it online!

This is an atop of a train

1∘↓+/⌽(⌽⍳7)∘~
(⌽⍳7)∘~ ⍝ Right side of the atop
⍳7    ⍝ Range
⌽      ⍝ Reverse
∘  ⍝ Composed with...
~ ⍝ ...without (to remove our arguments)
⌽        ⍝ Rotated by...
+/         ⍝ ...the sum of the arguments
1∘↓           ⍝ Left side of the atop
1∘↓           ⍝ Drop leftmost (drop curried with 1)
`