Group Integers by Originality
Python 3, 565 564 524 523 500 437 399 394 393 389 385 372 bytes
Brute-force implementation using itertools
; not all test-cases run within the 60 second limit on TIO.
Try it online!
Thanks to ArBo for golfing 101 bytes, to Galen Ivanov for golfing 19 bytes, to ElPedro for golfing 5 bytes, to movatica for golfing 17 bytes, to Black Owl Kai for golfing 2 bytes, to squid for golfing 2 bytes and to Kevin Cruijssen for golfing 1 byte.
from itertools import*
w=permutations
def c(l,x):
for i in range(9):
for q in w(map(abs,sum(l,[]))):
for s in w(q[:i+1]*len(x)):
z='';s=[*s]
while x[len(z):]:
z+=str(s.pop(0))
if z==x:return 9-i
return 0
def f(a):
l=[[]for _ in a*6]
for x in a:l[(x in sum(l,[]))*11or(-x in sum(l,[]))*10or any(l)and c(l,str(abs(x)))]+=x,
return[*filter(len,l)]
Explanation:
from itertools import *
w = permutations # We'll be using this twice
def c # Helper function to calculate which group a number belongs in according to the concatenation rule; returns 0 (original) if none is found
(l, x): # First parameter is the list of groups (a list of lists of numbers), second parameter is the number to investigate
for i in range(9): # There won't be any concatenations of more than 9 elements
for q in w(map(abs,sum(l,[]))): # Flatten l to get a plain list of previous numbers, then generate permutations of their absolute values as lists; for each permutation ...
for s in w(q[:i+1]*len(x)): # ... use only the first i + 1 elements; inflate the list with enough copies to compose the target number and permutate; then try to compose the target number from each permutation:
z = '' # Start with the empty string
s = [*s] # Convert permutation to list
while x[len(z):]: # Keep going until the length of the concatenated string equals the length of the target number
z += str(s.pop(0)) # Concatenate the first element of the current permutation list and remove it
if z == x: # If the target number has been synthesized successfully ...
return 9 - i # stop searching and return the appropriate group
return 0 # If no concatenation has been found, consider the number original
def f(a): # Solution function, takes a list of numbers as argument
l = [[] for _ in a * 6] # Populate the result list with at least 12 empty groups if there is more than one number in the input (we'll be using only the first 12 and removing empty ones later); if there is just one, we'll only need one group in the output
for x in a: # For each number in order:
l[(x in sum(l, [])) * 11 or (-x in sum(l, [])) * 10 or any(l) and c(l, str(abs(x)))] += x, # If x is not the first number, attempt concatenation (if not, c(l, str(abs(x))) would crash due to l not containing any non-empty sublists; use absolute value of the number under investigation; convert to string since we'll be needing the number of digits and comparing it to a string later); if -x has already been seen, put it in Group X; if x has already been seen, put it in Group X + 1
return [* filter(len, l)] # Remove empty lists and return the result
Python 2, 406 379 374 373 372 368 355 bytes
Same approach, but shorter due to some golfing tricks Python 3 doesn't support any more. Thanks to ArBo for the backport and for golfing 28 bytes, to ElPedro for golfing 5 bytes, to movatica for golfing 17 bytes, and to squid for golfing 1 more byte.
from itertools import*
w=permutations
def c(l,x):
for i in range(9):
for q in w(map(abs,sum(l,[]))):
for s in map(list,w(q[:i+1]*len(x))):
z=''
while x[len(z):]:
z+=`s.pop(0)`
if z==x:return 9-i
return 0
def f(a):
l=[[]for _ in a*6]
for x in a:l[(x in sum(l,[]))*11or(-x in sum(l,[]))*10or any(l)and c(l,`abs(x)`)]+=x,
return filter(len,l)
Try it online!
05AB1E, 43 41 38 35 27 bytes
.¡IN£UÄ.œεgΘ>XÄyÙå;P*}àXyå+
Try it online!
Explanation:
.¡ # group by:
IN£ # first N elements of the input, N being the iteration count
U # store this as X
Ä # absolute value of the current number
.œ # partitions (eg 449 => [[4, 4, 9], [44, 9], [4, 49], [449]])
ε } # map each partition to:
gΘ> # 2 if length = 1, 1 otherwise
yÙ # for each unique element in the current partition:
XÄ å # 1 if it's in the absolute value of X, 0 otherwise
; # divide all by 2
P* # product of all these numbers
à # take the maximum
Xyå+ # add 1 if X contains the current number
Since group numbers aren't part of the output, we're free to use any numbers we want, as long as the order is correct. This uses 0 for original numbers, 2^-N for group X-N, 1 for group X, 2 for group X+1.
Python 2, 235 234 232 246 245 244 241 240 238 237 236 bytes
from itertools import*
s=[];r=map(list,[s]*12)
for e in input():r[-(e in s)or max([10*(-e in s)]+[10-len(set(p[:i]))for p in permutations(`abs(x)`for x in s*11)for i in range(len(p))if''.join(p[:i])==`e`])]+=e,;s+=e,
print filter(len,r)
Try it online!
-1 byte thanks to Squid's comment on the other Python answer
This answer has no hopes of solving any but the most trivial of test cases. In the TIO link, s*11
has been replaced by s*2
, sacrificing correctness in some cases for faster execution time, but as far as I can see, the version in this post always yields the correct answer, in theory.
Explanation
from itertools import* # So that we can abuse permutations
s=[]; # s will hold the already classified numbers
r=map(list,[s]*12) # r will hold these too, but in the form of
# a nested list, sorted by originality
for e in input(): # Here comes the big one; iterate over the input
r[-(e in s)or # If e has already passed, it is not original
max([10*(-e in s)]+ # Else, we count 10 - the number of seen elements
# needed to make this one, or 0 if it's new,
# or 10 if its inverse has already passed
[10-len(set(p[:i])) # The number of distinct elements in...
for p in permutations( # for each permutation of the seen elements,
`abs(x)`for x in s*11)
# with values occuring up to 10 times (to
# account for 1111111111, for example;
# we need 11 here and not 10, because
# p[:i] doesn't include i)...
for i in range(len(p)) # each prefix...
if''.join(p[:i]) # only if its concatenation is equal to
==`e`])] # the current element
+=e,;s+=e, # Append the element to the relevant lists
print filter(len,r) # And finally, print the non-empty result lists