7-segment differences

I think most people around here know what a 7-segment display for digits is:

 _         _   _         _    _    _    _    _
| |    |   _|  _|  |_|  |_   |_     |  |_|  |_|
|_|    |  |_   _|    |   _|  |_|    |  |_|   _|


We can define the 7-segment difference (7SD) between two digits to be the number of segments that need to be toggled to switch from one to the other. E.g. the 7SD between 1 and 2 is 5 (the three horizontal segments and the lower two vertical segments need to be toggled), and the 7SD between 6 and 8 is 1.

Furthermore, we can define the 7SD between two numbers to be the sum of 7SDs between their corresponding digits. If one number is longer than the other, we assume they are right-aligned and add the number of segments needed to display the additional most-significant digits of the larger number. As an example, consider the 7SD between 12345 and 549:

  x:  1 2 3 4 5
y:      5 4 9
7SD:  2+5+2+0+1 = 10


Your task is to compute 7SD between n and n+1, given n.

For convenience, here is the full table of 7SDs between individual digits. The row _ represents an empty position.

   _ 0 1 2 3 4 5 6 7 8 9

_  0 6 2 5 5 4 5 6 3 7 6
0  6 0 4 3 3 4 3 2 3 1 2
1  2 4 0 5 3 2 5 6 1 5 4
2  5 3 5 0 2 5 4 3 4 2 3
3  5 3 3 2 0 3 2 3 2 2 1
4  4 4 2 5 3 0 3 4 3 3 2
5  5 3 5 4 2 3 0 1 4 2 1
6  6 2 6 3 3 4 1 0 5 1 2
7  3 3 1 4 2 3 4 5 0 4 3
8  7 1 5 2 2 3 2 1 4 0 1
9  6 2 4 3 1 2 1 2 3 1 0


Input

• Input is a single positive integer n.
• You may write a program or function, taking input via STDIN (or closest alternative), command-line argument or function argument.
• You may assume that the input is at most one less than the largest number which can be represented by your language's standard integer type, as long as that type supports at least values up to and including 127.

Output

• You should print a single integer, the 7SD between n and n+1.
• You may output via STDOUT (or closest alternative), function return value or function (out) argument.

Scoring

Standard rules apply, shortest code (in bytes) wins.

Test Cases

For some obscure reason, this sequence isn't in OEIS yet, although there is the closely related sequence A123587. Here are the first 100 numbers (starting with n = 1, 2, 3, ...):

5, 2, 3, 3, 1, 5, 4, 1, 4, 4, 5, 2, 3, 3, 1, 5, 4, 1, 7, 4, 5, 2, 3, 3, 1,
5, 4, 1, 4, 4, 5, 2, 3, 3, 1, 5, 4, 1, 5, 4, 5, 2, 3, 3, 1, 5, 4, 1, 5, 4,
5, 2, 3, 3, 1, 5, 4, 1, 3, 4, 5, 2, 3, 3, 1, 5, 4, 1, 7, 4, 5, 2, 3, 3, 1,
5, 4, 1, 6, 4, 5, 2, 3, 3, 1, 5, 4, 1, 3, 4, 5, 2, 3, 3, 1, 5, 4, 1, 6, 4


The first input for which the 7SD is greater than 9 is 1999 which should yield 11. Here are some other larger examples:

n          7SD
1999        11
12345        1
999999      14
5699999     15
8765210248   1


Jelly, 252221 20 bytes

‘DṁDḟ"DFị9979482ḃ5¤S


Background

We first increment the input n and discard all digits of n + 1 that haven't changed.

For example, if n is 5699999, we get the following.

n     : 5700000
n + 1 : 5699999
Result:  700000


All digits in this result have a fixed number of segments that have to get toggled. We can convert the list of toggles to bijective base 5 to save some bytes.

digit:   1 2 3 4 5 6 7 8 9 0
toggles: 4 5 2 3 3 1 5 4 1 2


The output is simply the sum of the individual toggles.

This works for most values of n, but special care must be taken if n + 1 has more digits than n. In this case, all digits must be 9's, and we solve this problem by chopping off a trailing 0 from n + 1.

For example, if n is 999999, we get the following.

n     :  999999
n + 1 : 1000000
Result: 100000


This works because the leading 1 evaluates to 4 toggles (distance between 0 and 1), while the actual amount of toggles is 2 (distance between 0 and 1), and suppressing one trailing 0 removes its 2 toggles from the sum.

How it works

‘DṁDḟ"DFị9979482ḃ5¤S  Main link. Argument: n

‘                     Compute n+1.
D                    Convert n+1 from integer to base 10.
D                  Convert n from integer to base 10.
ṁ                   Mold the left result as the right result.
This chops of a 0 if n+1 has more digits than n.
ḟ"D               Vectorized filter-false with the base 10 digits of n.
This removes the digits from n+1 that are identical to
the corresponding digits of n.
F              Flatten the resulting list of lists.
9979482ḃ5¤   Convert 9979482 to bijective base 5.
This yields [4, 5, 2, 3, 3, 1, 5, 4, 1, 2].
ị             Retrieve the digits at the right that correspond to the
indices at the left.
S  Compute the sum of the results.


JavaScript (ES6), 46 40 bytes

f=n=>n?+"452331541"[n%10]||f(n/10|0)+2:2


Alternative formulation, also 46 40 bytes:

f=n=>n?26523308>>n%10*3&7||f(n/10|0)+2:2


Edit: Saved 6 bytes thanks to @xsot.

• If the logical or operator in ES6 behaves like the one in python you can further shorten your second code. Refer to my submission for an example. – xsot Jun 13 '16 at 5:11
• @xsot Actually I can shorten both! I don't think it helps me to change the zero special-case because that's only 4 bytes as it is. – Neil Jun 13 '16 at 7:47
• Wow, I'm surprised that the first one works. I expected an error. – xsot Jun 13 '16 at 8:42
• @xsot javascript does not simply error out. It just does whatever seemed like the most correct approach during those ten days Javascript was born. . Later versions let you opt into an a bit stricter behavior, but why would anyone here do that? Shortcircuiting behavior of logical operators is pretty common, though, only PHP doing the wrong thing by always returning a boolean. – John Dvorak Jun 14 '16 at 7:27
• @JanDvorak Actually, I was surprised by the fact that you can access an index of a string bigger than the length of the string. – xsot Jun 14 '16 at 8:43

Python, 50 48 bytes

f=lambda n:26523308-0**n*2>>n%10*3&7or f(n/10)+2


Explanation

This function operates on the least significant digit of the number n, summing the 7SD of the digits when incremented by one until after the first non-9 digit.

26523308 is a bitmask that encodes the mapping for the digits 0-8. When n=0, which only occurs when n comprises only 9s, the answer will be off by two. This is compensated by the expression 0**n*2. As for the digit 9, the bitmask evaluates to zero which will trigger the recursive call while adding 2 to the 7SD.

• Can we have some explanation of how this does the transformation? I mean, +1 for cleverness but I got lost in the clever. – CAD97 Jun 13 '16 at 19:47

05AB1E, 31302827 26 bytes

Code:

9Ü©T%•2X›ùì•sè¹g®g-·¹Ú9Q·O


Explanation (outdated):

9Ü                              # Trim off trailing 9's
©                             # Copy this into the register
T%                           # Get the last non-9 digit
žh                         # Short for 0123456789
•2X›ùì•§                 # Compressed version of 4523315412
‡                # Transliterate


We are changing the following to the last non-9 digit:

0 -> 4
1 -> 5
2 -> 2
3 -> 3
4 -> 3
5 -> 1
6 -> 5
7 -> 4
8 -> 1
9 -> 2


For the special cases:

                ¹g              # Get the length of the input
®g            # Get the length of the input with all trailing 9 gone
-           # Substract, giving the number of 9's at the end of
the input
2*         # Multiply by two
O        # Sum everything up
¹Ú      # Uniquify the input
9Qi   # If this is equal to 9 (only 9's in the input)
Ì  #   Increment by 2 (_ -> 1)


Uses the CP-1252 encoding. Try it online!.

28 byte alternative: D[¤©•2X›ùì•sès®9Ê#¨]\rÚ9Q4*O.

Java, 63 bytes

The world is righted as Python passes Java once more.

Cause, ya know, Java.

int f(int n){return n>0?n%10<9?26523308>>n%10*3&7:2+f(n/10):2;}


See it on ideone

Maxes out at 2147483647, as that is Java's Integer.MAX_VALUE.

This is a port of my Python answer which is a port of the ES6 answer.

MATL, 6139 36 bytes

tQvV15\'3dAsMh818RG5'6Y27WZaw)Z}Z~Bz


Try it online!

Explanation

tQv            % Implicit input. Duplicate, add 1, concatenate vertically
V              % Convert to 2D char array: each number in a row, possibly left-padded
% with a space
15\            % Modulo 15. With modular indexing this corresponds to the order
% '9', ' ', '0', '1', ..., '8'
'3dAsMh818RG5' % This string encodes active segments for each of the 11 chars
6Y2            % Source alphabet printable ASCII chars (predefined literal)
7W             % Target alphabet: [0 1 ... 127]
Za             % Base conversion: decode string into vector of 11 numbers, where each
% number from 0 to 127 encodes the 7-segment representation of a digit,
% in the order '9', ' ', '0', '1', ..., '8'
w              % Swap top two elements in stack
)              % Use as index. Gives 2-row array, where each column is a digit
Z}             % Split into the two rows
Z~             % Bitwise XOR, elementwise
B              % Convert to binary. Each number gives a row
z              % Number of nonzero elements. Implicitly display


Julia, 44 bytes

!x=x<1?2:(t=x%10÷1)<9?3045058÷6^t%6:2+!.1x


Try it here.

Dennis saved a byte!

• Out of curiosity, why not just use the numbers? – Conor O'Brien Jun 12 '16 at 22:33
• I can't believe there's a Julia TIO. Welp, time to learn Julia then... – Mama Fun Roll Jun 14 '16 at 4:58

Python, 71 66 bytes

48 bytes by xsot. Even more magic maths!

f=lambda n:(2+f(n/10)if n%10==9else 26523308>>n%10*3&7)if n else 2


See it on ideone

Because the prior Python answer doesn't work and is far from optimal. A simple port of a previous ES6 version. Now using bit twiddling (from the ES6 alternate formulation) to cut out a cast!

Can be made to work with Python 3 by explicitly using floordiv for +1 byte.

• you can take out the space after 9 – Maltysen Jun 13 '16 at 1:26
• @Maltysen apparently you are correct. I thought it would error because e is a valid letter after a num in, for example, 9e9. – CAD97 Jun 13 '16 at 1:30
• This is longer than my Java answer! How can we remedy this? Note that reversing the comparison from n%10==9 to n%10<9 doesn't save as the if doesn't need a space in this order. – CAD97 Jun 13 '16 at 2:23
• And I come back to see xsot has made a much shorter Python version. Well done! – CAD97 Jun 13 '16 at 19:50

Jolf, 32 bytes

Ώ?H?<γ%Ht9P."452331541"γ+2Ώc/Ht2


Try it here!

Explanation

This is a transpilation of Neil's answer.

Ώ?H?<γ%Ht9P."452331541"γ+2Ώc/Ht2
Ώ                                 define a function Ώ of H
?H                            2  (when H is zero, return is 2)
%Ht                         H mod 10
γ                            γ = ^
?<    9                        is it less than 9?
if so:
."452331541"γ           get the γth element of that string
P                        as a number
else
Ώ        Ώ over
c/Ht    int(H / 10)


Pyth - 7830 27 bytes

That first one was embarrassing.

s@LjC"
(J"ThC{I#.tjRThBQT


J, 53 bytes

2:((2+10$:@<.@%~[)(6|3045058<.@%6^])@.(9>])10&|)@.*  Originally based on @Neil's solution. Then improved by saving a byte using the same formula in @Lynn's solution. The 54 byte version based on the string is 2:((2+10$:@<.@%~[)('452331541'".@{~])@.(9>])10&|)@.*


   f =: 2:((2+10$:@<.@%~[)(6|3045058<.@%6^])@.(9>])10&|)@.* f 1999 11 f 1999 12345 999999 5699999 8765210248 11 1 14 15 1  Retina, 34 bytes M!.9*$
^9
0
Td4523315412
.
$* .  Try it online! (The first line just allows the processing of multiple test cases at once.) Explanation Like most answers have discovered by now, we don't need to use the full table, since only the least-significant non-9 digit changes when incrementing. That's also how this answer works. M!.9*$


This matches (M) the regex .9*$ i.e. the first digit that is only separated by 9s from the end. The ! tells Retina to replace the input with this match, discarding everything that doesn't affect the 7SD. ^9 0  If the input now starts with a 9 that means, the input itself consisted only of 9s, so the 7-segment display needs to prepend a 1 which costs 2. The simplest way to handle this is to replace the leading 9 in this case with a 0, since the cost of incrementing a 9 (to 0) is 2 and the cost of incrementing 0 (to 1) is 4, so this raises the overall cost by 2 as required. Td4523315412  Now we have a transliteration stage which replaces each digit with its cost for incrementing it (since the d expands to 0123456789). Note that this is the first subdiagonal of the 7SD table. .$*


This replaces each digit n with n copies of 1, i.e. it converts each digit to unary, and since there are no separators immediately adds them together.

.


Finally, we count the number of characters (i.e. number of matches of .) in the result, which converts the unary sum back to decimal.