Several bases but not twice the same digit

15

0

Input

A non-empty array of positive integers.

Task

Convert each integer to either binary, octal, decimal or hexadecimal in such a way that each digit (0 to F) is used at most once.

Output

The list of bases that were used to solve the puzzle.

Detailed example

The expected output for [ 16, 17 ] is [ octal, decimal ].

Here is why:

  • We can't simply use decimal for both numbers, because they both contains a 1.
  • 16 cannot be converted to binary, because its representation in this base (10000) contains several 0's.
  • 17 cannot be converted to binary either, because its representation in this base (10001) contains several 0's and several 1's.
  • 17 cannot be converted to hexadecimal, because its representation in this base (11) consists of two 1's.
  • Let's consider all remaining possibilities:

                   +---------+---------+--------+
                   | oct(16) | dec(16) | hex(16)|
                   | = 20    | = 16    | = 10   |
    +--------------+---------+---------+--------+
    | oct(17) = 21 | 20,21   | 16,21   | 10,21  |
    | dec(17) = 17 | 20,17   | 16,17   | 10,17  |
    +--------------+---------+---------+--------+
    

    The only possible solution is to convert 16 in octal (20) and to keep 17 in decimal (17). This way, the digits 0, 1, 2 and 7 are used exactly once.

Clarifications and rules

  • The input is guaranteed to lead to a unique solution. Your code is not supposed to support arrays that give several solutions or no solution at all.
  • You may output the bases in any reasonable format, such as [ "bin","oct","dec","hex" ], [ 'b','o','d','h' ], "BODH", [ 2,8,10,16 ], [ 0,1,2,3 ] etc. But it should be clearly explained in your answer.
  • The order of the bases in the output must match the order of the input integers.
  • If that helps, you may assume that the input is sorted from lowest to highest, or from highest to lowest.
  • This is , so the shortest answer in bytes wins!

Test cases

You do not have to output the conversion results listed below. They are purely informational.

Input                                  | Output          | Conversion result
---------------------------------------+-----------------+------------------------
[ 119 ]                                | O               | 167
[ 170 ]                                | D               | 170
[ 64222 ]                              | H               | FADE
[ 16, 17 ]                             | O/D             | 20/17
[ 14, 64, 96 ]                         | H/H/D           | E/40/96
[ 34, 37, 94 ]                         | O/D/H           | 42/37/5E
[ 2, 68, 82 ]                          | B/D/H           | 10/68/52
[ 22, 43, 96 ]                         | O/O/O           | 26/53/140
[ 3639, 19086, 57162 ]                 | H/D/H           | E37/19086/DF4A
[ 190, 229, 771 ]                      | O/H/O           | 276/E5/1403
[ 2, 44, 69, 99 ]                      | B/H/H/H         | 10/2C/45/63
[ 75, 207, 218, 357, 385 ]             | H/H/H/D/O       | 4B/CF/DA/357/601
[ 12, 28, 46, 78, 154, 188, 222, 240 ] | D/O/O/D/H/H/H/H | 12/34/56/78/9A/BC/DE/F0

The raw input list is available here.

Arnauld

Posted 2018-04-05T15:57:03.307

Reputation: 111 334

should we care about some aspect of efficiency? (like if the array is of length 1000 or something like that) – DanielIndie – 2018-04-05T16:06:20.593

3@DanielIndie No, you don't have to. Besides, a puzzle of 1000 entries would include a lot of duplicate digits, no matter the bases that are used, so it can't possibly be a valid one. (This is guaranteed not to happen as per the first rule.) – Arnauld – 2018-04-05T16:10:45.363

yes, you are right... stupid me... :) – DanielIndie – 2018-04-05T16:51:41.240

1Really looking forward to a Japt solution, because I tried it out and couldn't find a good one. – Nit – 2018-04-05T17:13:49.510

Can we output the list of bases with each as a number in its own base? For example, for [16, 17]: [10, 10] (8 in octal, 10 in decimal)? – Khuldraeseth na'Barya – 2018-04-05T22:43:10.967

2@Scrooble Nope. :) Nice try! – Arnauld – 2018-04-05T22:50:41.317

Answers

4

JavaScript (Node.js),192,155,154,152,151,145,136,113,99,92 90 bytes

  • thanks to @Arnauld for reminding me that i can return [0,1,2,3] -> which is [2,8,10,16] saves 8 bytes, and for the brilliant idea (which help to reduce by 23+ bytes)
  • thanks to @Kevin Cruijssen for reducing by 1 bytes
f=([c,...a],t="")=>c?[1,4,5,8].find(b=>T=!/(.).*\1/.test(n=t+c.toString(b*2))&&f(a,n))+T:a

Try it online!

Explanation:

[c,...a] - @Arnauld trick for taking one item at a time c?***:" " ->if c is undefined we managed to get to the end result- [] - if i would put "" than the find would not considered that legit. ([]+5="5" JS FTW) [1,4,5,8].find every time we find the correct base (the output will be of this array (1,4,5,8)->(2,8,10,16) its legit. now how the find works -> if it finds something it returns the element (1-8) and than i add the result of the inner solution. if it doesnt find then it returns undefined + T is now false -> NaN which in the parent call will be considered false

!/(.).*\1/.test(n=t+b) determine if the string has duplicates, if so:

f(a,n)) just go the the next number(a is now array.slice(1)) with the new string(n)

we assign result to T(temp) of the result because find stops when it finds and so we know that the last result will be f() which is result B

DanielIndie

Posted 2018-04-05T15:57:03.307

Reputation: 1 220

1t="",B="" to t="",B=t would save a byte. – Kevin Cruijssen – 2018-04-06T07:32:38.030

@KevinCruijssen updates the solution, thanks :) (and you to Arnauld) – DanielIndie – 2018-04-06T07:48:29.347

@Arnauld i took your brilliant idea and did something similiar. look at the solution now – DanielIndie – 2018-04-06T08:34:04.987

@Arnauld pure awesomeness – DanielIndie – 2018-04-06T15:16:14.923

@Arnauld watch the new version :) managed to get to 92. i hope trailing spaces are allowed :) – DanielIndie – 2018-04-06T15:58:25.753

1

Cool! Let's shave off 2 more bytes (and no need to trim() anymore).

– Arnauld – 2018-04-06T16:03:39.363

3

Perl 5 -alp, 55 bytes

Uses %x for hex, %d for decimal, %o for octal and %b for binary

#!/usr/bin/perl -alp
($_)=grep{sprintf($_,@F)!~/(.).*\1/}glob"%{d,o,b,x}"x@F

Try it online!

Ton Hospel

Posted 2018-04-05T15:57:03.307

Reputation: 14 114

3

Ruby, 72 71 bytes

->a{a.map{%w[b o d x]}.inject(&:product).find{|c|/(.).*\1/!~[p,c]*?%%a}}

Output format is some kind of reverse S-expression monstrosity:

f[[12, 28, 46, 78, 154, 188, 222, 240]]
=> [[[[[[["d", "o"], "o"], "d"], "x"], "x"], "x"], "x"]

Slash-separating it instead would cost 3 more bytes (appending *?/).

This format comes from the loop structure, slightly shorter than the more idiomatic repeated_combination(a.size), which generates an array of arrays of characters and then reduces it over the cross-product function.

Edit: Saved 1 byte thanks to Lynn.

histocrat

Posted 2018-04-05T15:57:03.307

Reputation: 20 600

2

Jelly, 17 16 bytes

⁴⁽%ʠḃṗL³bF⁼Q$ƲÐf

Try it online!

Return a list of bases.

 == Explanation ==
⁴⁽%ʠḃṗL³bF⁼Q$ƲÐf  Main link.
 ⁽%ʠ              A number.
    ḃ             convert it to bijective base...
⁴                   16. The result is [2,8,10,16].
     ṗL           Cartesian power by the input length.
             ƲÐf  Filter, keep those that satisfies...
       ³            the input
        b           convert to that base
         F          when flatten (join all the digits of \
                      different numbers together)
          ⁼Q$       equal to itself uniquified.

user202729

Posted 2018-04-05T15:57:03.307

Reputation: 14 620

2

Pyth, 21 20 bytes

f{Is.bjYNTQ^[8T2y8)l

Returns a list of all possible lists of bases (which always has length 1).
Try it here

Explanation

f{Is.bjYNTQ^[8T2y8)l
           ^[8T2y8)lQ  Get the tuples of bases of the same length as the input.
f                      Filter to get those...
    .bjYNTQ            ... where converting bases elementwise...
   s                   ... and joining together...
 {I                    ... has no repeats.

user48543

Posted 2018-04-05T15:57:03.307

Reputation:

2

Wolfram Language (Mathematica), 71 bytes

Cases[2{1,4,5,8}~Tuples~Tr[1^#],b_/;UnsameQ@@Join@@IntegerDigits[#,b]]&

Return a list of bases.

Try it online!

alephalpha

Posted 2018-04-05T15:57:03.307

Reputation: 23 988

2

Python 2, 128 bytes

from itertools import*
a=input()
for b in product(*['bdxo']*len(a)):
 s=''.join(map(format,a,b))
 if len(s)==len(set(s)):print b

Try it online!

Lynn

Posted 2018-04-05T15:57:03.307

Reputation: 55 648

2

05AB1E, 17 bytes

2žv8T)sgãʒIsв˜DÙQ

Try it online!

Kaldo

Posted 2018-04-05T15:57:03.307

Reputation: 1 135

I don't know 05AB1E, so perhaps I should wait until you've added an explanation before I ask this, but why is the result for 8 the character '8', and the other three an integer? +1 though, seems to work just fine, including the longer last test cases. – Kevin Cruijssen – 2018-04-06T15:21:25.170

2@KevinCruijssen That's coming from "2žv8T". Numbers in the source code are pushed as characters in 05AB1E, whereas žv (16) and T (10) are built-ins that pushes their respective numbers on the stack. This usually goes unnoticed because 05AB1E's implicit display of the last element in the stack converts to numbers, but since in this case the displayed result is an array of elements, those elements are left untouched, hence the quotes. The command ï for example can be used after ) to cast the two char elements to ints. – Kaldo – 2018-04-06T15:33:11.443

@KevinCruijssen Example of my explanation: https://tio.run/##MzBNTDJM/f/fyPbQDtv//wE The code: push 2, print, wrap into an array, print.

– Kaldo – 2018-04-06T15:42:39.783

2

Python 2, 121 117 113 111 bytes

def f(a,d='',s=''):
 if a:
	for c in'bodx':t=format(a[0],c)+s;len(t)-len(set(t))or f(a[1:],d+c,t)
 else:print d

Try it online!

Tip of the hat to Lynn for format, which I had forgotten!

Chas Brown

Posted 2018-04-05T15:57:03.307

Reputation: 8 959

1

Husk, 19 bytes

fȯS=UΣz`B¹πmDd1458L

Try it online!

Returns lists of bases

Explanation

fȯS=UΣz`B¹πmDd1458L  Implicit input
                  L  Length of input
          π          Cartesian power of
             d1458     The digits of 1458  [1,4,5,8]
           mD          Double the digits   [2,8,10,16]
fȯ                   Filter by
      z`B¹             Zip with input by converting to its base
     Σ                 Concatenate
  S=U                  Equal to itself with unique elements

Fyr

Posted 2018-04-05T15:57:03.307

Reputation: 561