Challenge
Given a sequence of numbers, create a function which returns the sequence steps.
- Assume a sequence will be
N >= 3 - Sequence will repeat it steps at least once
- Sequence will only contain natural numbers
- Your function or program should return the shortest possible sequence of steps
Example:
Input: [1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17]
Output: [1, 1, 2]
Explanation: The initial sequence goes from 1 => 2 (1 step), 2 => 3 (1 step), 3 => 5 (2 steps). Then it repeats. The output then is [1 step, 1 step, 2 steps] => [1, 1, 2]
Another example:
Input: [2, 5, 6, 7, 8, 11, 12, 13, 14, 17, 18, 19, 20]
Output: [3, 1, 1, 1]
[2, 5, 6, 7, 8, 11, 12, 13, 14, 17, 18, 19, 20]
\ /\ /\ /\ /
3 1 1 1 Then it repeats...
Test Cases
Input: [1, 4, 8, 9, 10, 13, 17, 18, 19, 22, 26, 27, 28] => Output: [3,4,1,1]
Input: [6, 11, 13, 18, 20, 25, 27, 32, 34, 39, 41] => Output: [5,2]
Input: [2, 6, 10, 13, 17, 21, 25, 28, 32, 36, 40, 43, 47] => Output: [4,4,3,4]
Input: [5, 6, 7] => Output: [1]
Clarifications
- The input length - 1 is divisible by the output length
- Assume sequence will always going to be increasing
This is code-golf, so the shortest answer in bytes win.
-
\$\begingroup\$ Related challenge. \$\endgroup\$AdmBorkBork– AdmBorkBork2018年06月05日 13:45:17 +00:00Commented Jun 5, 2018 at 13:45
-
7\$\begingroup\$ I've seen a few challenges you've posted recently with a lot of clarifying comments, and a couple closed as "unclear", and subsequently re-opened after you've made the appropriate edits. Have you considered posting these in the sandbox for a few days/a week? I've enjoyed your challenges since they're quite approachable, but all challenges, no matter how simple or by whom they're posted, can use refinement. \$\endgroup\$Giuseppe– Giuseppe2018年06月05日 14:13:11 +00:00Commented Jun 5, 2018 at 14:13
-
2\$\begingroup\$ @Giuseppe Thanks for your suggestions. I have posted some other challenges in the sand box (usually if i don't get the right way to create a challenge with it i delete it). For these challenges I thought they were clear enough and that's why I posted immediately but I will start posting them in the sandbox first. Thanks \$\endgroup\$Luis felipe De jesus Munoz– Luis felipe De jesus Munoz2018年06月05日 14:15:57 +00:00Commented Jun 5, 2018 at 14:15
-
2\$\begingroup\$ @LuisMendo Heretic! 0 is a natural number! Billy Joel even had a whole album dedicated to the Peano Man! \$\endgroup\$ngm– ngm2018年06月05日 15:46:56 +00:00Commented Jun 5, 2018 at 15:46
-
1\$\begingroup\$ @AdmBorkBork, this is more related by virtue of dealing with arbitrary-length operation lists. \$\endgroup\$Peter Taylor– Peter Taylor2018年06月06日 06:29:26 +00:00Commented Jun 6, 2018 at 6:29
25 Answers 25
Jelly, (削除) 9 (削除ここまで) 7 bytes
IsJEƇḢḢ
How it works
IsJEƇḢḢ Main link. Argument: A (array)
I Increment; compute D, the array of A's forward differences.
J Indices; yield [1, ..., len(A)].
s Split D into chunks of length k, for each k in [1, ..., len(A)].
EƇ Comb equal; keep only partitions of identical chunks.
Ḣ Head; extract the first matching parititon.
Ḣ Head; extract the first chunk.
JavaScript (ES6), 58 bytes
Outputs a comma-separated string (with a leading comma).
a=>(a.map(p=x=>-(p-(p=x)))+'').match(/N((,\d+)*?)1円*$/)[1]
Or 56 bytes if we use ,- as the separator and we assume that the sequence is always strictly increasing.
How?
We first convert the input array a[ ] to a list of consecutive differences with:
a.map(p = x => -(p - (p = x)))
Because p is initially set to a non-numeric value (the callback function of map()), the first iteration yields NaN.
Example:
[6, 11, 13, 18, 20, 25, 27, 32, 34, 39, 41]
[ NaN, 5, 2, 5, 2, 5, 2, 5, 2, 5, 2 ]
We then coerce the result to a string:
"NaN,5,2,5,2,5,2,5,2,5,2"
Finally, we look for the shortest1 pattern of comma-separated integers (,\d+) starting right after "NaN" and repeating till the end of the string:
match(/N((,\d+)*?)1円*$/)
1: using the non-greedy *?
-
\$\begingroup\$ I'm posting a solution based on the same regex idea, but very different in implementation. Of course I did not look at other solutions before developing mine, and it seems different enough, And maybe it's the first time ever I manage to score better than you here. \$\endgroup\$edc65– edc652018年06月06日 07:28:33 +00:00Commented Jun 6, 2018 at 7:28
-
1\$\begingroup\$ 53 bytes:
/(,.+?)1円*$/. \$\endgroup\$Neil– Neil2018年06月06日 09:54:12 +00:00Commented Jun 6, 2018 at 9:54
Brachylog, 11 bytes
s2f-mṅm~j(t
Would be 5 bytes if there was a built-in for consecutive differences.
Explanation
Example input: [6, 11, 13, 18, 20, 25, 27, 32, 34, 39, 41]
s2f Find all substrings of length 2: [[6,11],[11,13],...,[34,39],[39,41]]
-m Map subtraction: [-5,-2,-5,-2,-5,-2,-5,-2,-5,-2]
ṅm Map negate: [5,2,5,2,5,2,5,2,5,2]
~j( Anti-juxtapose the list of differences; the shortest repeated list is found
first, with the biggest number of repetitions: [5,[5,2]]
t Tail: [5,2]
-
\$\begingroup\$ Can you negate after the tail, to save a byte? \$\endgroup\$Rod– Rod2018年06月05日 14:08:31 +00:00Commented Jun 5, 2018 at 14:08
-
\$\begingroup\$ @Rod I would still need to map it, so it would be the same length. Negate is a predicate between two numbers, it doesn't vectorize automatically to lists like other languages (otherwise it would not work well with unknown inputs/outputs which are common in declarative programs) \$\endgroup\$Fatalize– Fatalize2018年06月05日 14:10:45 +00:00Commented Jun 5, 2018 at 14:10
Pyth, 11 bytes
<J.+Qf.<IJT
Explanation
<J.+Qf.<IJT
J.+Q Call the sequence of differences in the input J.
f Find the first positive integer T...
.<IJT ... where rotating J by T doesn't change it.
<J Take that many elements of J.
Japt, (削除) 14 (削除ここまで) 12 bytes
äa
̄@eUéX}aÄ
Explanation
:Implicit input of array U
äa :Consecutive absolute differences
\n :Reassign to U
@ }aÄ :Return the first positive integer X that returns true
UéX : Rotate U right X times
e : Check equality with U
̄ :Slice U to that element
Original
äa
@eUîX}a@ ̄XÄ
R, (削除) 49 (削除ここまで) 46 bytes
Full program:
d=diff(scan());while(any((s=d[1:T])-d))T=T+1;s
R, (削除) 72 (削除ここまで) (削除) 58 (削除ここまで) 54 bytes
Original function submission with all test cases in one place:
function(a,d=diff(a)){while(any((s=d[1:T])-d))T=T+1;s}
Thanks to JayCe for suggesting the full program route and -4 bytes on the function, and to Giuseppe for further -3.
-
\$\begingroup\$ -9 bytes by abusing a built-in and making it a full program The challenge allows a full program. \$\endgroup\$JayCe– JayCe2018年06月05日 20:47:43 +00:00Commented Jun 5, 2018 at 20:47
-
\$\begingroup\$ @JayCe don't need
a<-here either \$\endgroup\$Giuseppe– Giuseppe2018年06月05日 21:05:09 +00:00Commented Jun 5, 2018 at 21:05
J, (削除) 22 (削除ここまで) 19 bytes
3 bytes saved thanks to FrownyFrog!
0{"1[:~./:|."{}.-}:
[Try it online!][TIO-ji2uiwla]
How?
- find the successive differences by subtracting
}: the list with last element dropped
}. from the list with the first element dropped
|."{ rotate the list of differences
/: 0..length-1 times (the input graded up)
[:~. remove duplicating rows
0{"1 take the first element of each row
-
\$\begingroup\$ If you
/:instead of#\, you can0{"1[:~.to save 1 byte. \$\endgroup\$FrownyFrog– FrownyFrog2018年06月06日 09:24:57 +00:00Commented Jun 6, 2018 at 9:24 -
\$\begingroup\$ And
"0 1is"{\$\endgroup\$FrownyFrog– FrownyFrog2018年06月06日 09:26:16 +00:00Commented Jun 6, 2018 at 9:26 -
\$\begingroup\$ @FrownyFrog Thanks, once again! \$\endgroup\$Galen Ivanov– Galen Ivanov2018年06月06日 10:48:41 +00:00Commented Jun 6, 2018 at 10:48
-
1\$\begingroup\$ this is gorgeous. \$\endgroup\$Jonah– Jonah2018年06月07日 04:19:48 +00:00Commented Jun 7, 2018 at 4:19
-
\$\begingroup\$ @Jonah Yes, thanks to FrownyFrog! \$\endgroup\$Galen Ivanov– Galen Ivanov2018年06月07日 06:14:53 +00:00Commented Jun 7, 2018 at 6:14
05AB1E, 8 bytes
Saved 3 bytes thanks to Kevin Cruijssen.
\.œʒË}нн
05AB1E, 11 bytes
āεI\ô}ʒË}нн
āεI\ô}ʒË}нн Full program. ā Length range. Push [1 ... len(inp)]. ε } For each... I\ô ... Chop the deltas into pieces of the corresponding size ʒË} Keep only those that have all their elements equal. нн And first retrieve the first element of the first one.
13 bytes
A cute alternative, IMO:
\©ηʒDg®ôÙ ̃Q}н
\©ηʒDg®ôÙ ̃Q}н Full program.
\ Push the deltas.
© Copy them to the register.
ηʒ } And filter the prefixes by...
D Q ... Is the prefix itself equal to...
g®ô ... The deltas, split into chunks of its length...
Ù ̃ ... Deduplicated and flattened?
н Head.
-
1\$\begingroup\$ 8 bytes by using
.œ. \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2019年05月08日 08:23:07 +00:00Commented May 8, 2019 at 8:23
Javascript, 49 (削除) 56 (削除ここまで) bytes
Edit 7 bytes saved thanks (guess who?) Arnauld
Same regex idea as Arnauld, but curiously so different in implementation ...
Returning a string with steps comma separated (and a leading comma)
p=>/N(.+?)1円+$/.exec(p.map(p=v=>[v-p,p=v][0]))[1]
Test
var F=
p=>/N(.+?)1円+$/.exec(p.map(p=v=>[v-p,p=v][0]))[1]
;[[1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17]
,[1, 4, 8, 9, 10, 13, 17, 18, 19, 22, 26, 27, 28]
,[6, 11, 13, 18, 20, 25, 27, 32, 34, 39, 41]
,[2, 6, 10, 13, 17, 21, 25, 28, 32, 36, 40, 43, 47]
,[5, 6, 7]]
.forEach(x=>console.log(x + ' -> ' + F(x)))
-
\$\begingroup\$ Using
matchwas a poor decision of mine. You can outgolf me some more. :-) \$\endgroup\$Arnauld– Arnauld2018年06月06日 07:49:52 +00:00Commented Jun 6, 2018 at 7:49
MATL, (削除) 14 (削除ここまで) (削除) 13 (削除ここまで) 12 bytes
dt5YLFTF#Xu)
Just discovered that MATL does have a circulant function!
Explanation
d - Get the differences between successive terms, as an array
t5YL - duplicate that, then call the YL ('gallery') function with 5 ('circulant') option. Creates a matrix with the given vector as first row, then successive rows are the same vector shifted circularly, until it wraps around.
FTF#Xu - Check for unique rows and get their row numbers (not sure if there's a shorter way of doing this). When sequence steps repeat, the circularly shifted row will be the same as the first row, and the subsequent rows will be repeats. So this gets the indices of the first run of sequence steps before they start repeating.
) - index using that into the original differences array, to get the answer.
Older:
d`tt@YS-a}@:)
(-1 byte thanks to Giuseppe)
Explanation:
d % Get the differences between successive terms, as an array
` % Start do-while loop
tt % duplicate the difference array twice
@ % push the current loop index value
YS % circularly shift the difference array by that amount
- % subtract the shifted diffs from the original diffs
a % see if the subtraction resulted in any non-zeros
% if it did, shifted differences were not equal to original differences, so continue loop
}@ % if it didn't, then get loop index
:) % get the differences upto the loop index, before they started repeating
% implicit loop end
Python 2, 101 bytes
def f(l):d=[y-x for x,y in zip(l,l[1:])];g=len(l);print[d[:k]for k in range(1,g+1)if g/k*d[:k]==d][0]
First generates the deltas d, then finds the first prefix p of d that when repeated ⌊len(L) / len(p)⌋ times yields L, where L is the input list.
Ruby, 62 bytes
Relies on Regex logic adapted from Arnauld's answer.
->a{i=-2;a.map{|x|(i+=1)>=0?x-a[i]:0}*?,=~/((,\d+)*?)1円*$/;1ドル}
Alternative determination of step differences, also 62 bytes:
->a{[0,*a.each_cons(2).map{|x,y|y-x}]*?,=~/((,\d+)*?)1円*$/;1ドル}
Java 10, (削除) 104 (削除ここまで) 100 bytes
a->{var t="";for(int i=a.length;i-->1;t+=a[i]-a[i-1]+" ");return t.replaceAll("( ?.+?)\1円*$","1ドル");}
Regex ( ?.+?)1円*$ for shortest repeating substring from @Neil's comment on @Arnauld's JavaScript (ES6) answer.
Explanation:
a->{ // Method with integer-array parameter and String return-type
var t=""; // Temp-String, starting empty
for(int i=a.length;i-->1; // Loop backward over the input-array, skipping the first item
t+=a[i]-a[i-1] // Calculate the difference between two adjacent items
+" "); // And append this with a space to the temp-String
return t.replaceAll("( ?.+?)\1円*$",
// Find the shortest repeating substring
"1ドル");}// And only keep one such substring
APL+WIN, 39 bytes
Prompt for input.
(↑((⍴v)=+/ ̈(⊂v)=(⍳⍴v)⌽ ̈⊂v)/⍳⍴v)↑v←-2-/⎕
Try it online! Courtesy of Dyalog Classic
Explanation:
v←-2-/⎕ Prompt for input and take successive differences
(⍳⍴v)⌽ ̈⊂v create a nested vector ans sequentially rotate by one to length of v
+/ ̈(⊂v)= compare to original v and sum positions where there is match
(⍴v)= identify where all elements match
(↑(....) identify number of rotations giving a first complete match
(↑(...)↑v take first number of elements from above from v as repeated sequence
Python 2, (削除) 86 (削除ここまで) 85 bytes
def f(a,n=1):d=[y-x for x,y in zip(a,a[1:])];return d[:-n]==d[n:]and d[:n]or f(a,n+1)
Construct the differences as d; if d repeats with unit size n then d[n:]==d[:-n]; else recurse.
Retina 0.8.2, 42 bytes
\d+
$*
(?<=(1+),)1円
1+(.+?)1円*$
1ドル
1+
$.&
Try it online! Link includes test cases. Output includes leading comma. Explanation:
\d+
$*
Convert to unary.
(?<=(1+),)1円
Compute forward differences, except for the first number, which gets left behind.
1+(.+?)1円*$
1ドル
Match repeating differences.
1+
$.&
Convert to decimal.
05AB1E, (削除) 14 (削除ここまで) 13 bytes
\DηvÐNƒÁ}QD—#
Try it online or verify all test cases.
I know there are already two shorter 05AB1E answers posted by @Mr.Xcoder, but I wanted to try this alternative approach using rotation and equality check.
Might be able to golf it down a few bytes without dropping Á.
-1 byte after a tip of @Emigna to remove the global_variable registers (© and 2x ®) and use a Duplicate (D) and a Triplicate (Ð) instead.
Explanation:
\ # Calculate the deltas of the input-array
# i.e. [1,2,3,5,6,7,9] → [1,1,2,1,1,2]
D # Duplicate it
η # Push all its prefixes
# [1,1,2,1,1,2] → [[1],[1,1],[1,1,2],[1,1,2,1],[1,1,2,1,1],[1,1,2,1,1,2]]
v # For-each over these prefixes
Ð # Triplicate the (duplicated) deltas-list
NƒÁ} # Rotate the deltas-list N+1 amount of times,
# where N is the prefix index (== prefix_length-1)
# i.e. [1,1,2] and [1,1,2,1,1,2] (rotate 3 times) → [1,1,2,1,1,2]
Q # If the rotated deltas and initial deltas are equal
# [1,1,2,1,1,2] and [1,1,2,1,1,2] → 1
D—# # Print the current prefix-list, and stop the for-each loop
-
1\$\begingroup\$ Here's a 9 (separate answer since it's a very different algo, though it does share the ¥η). \$\endgroup\$Grimmy– Grimmy2019年05月07日 15:47:10 +00:00Commented May 7, 2019 at 15:47
-
\$\begingroup\$ @Grimy Are you going through all my 05AB1E answers and golf each of them, haha? ;p Nice answer though (yet again), +1 from me. \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2019年05月07日 16:02:10 +00:00Commented May 7, 2019 at 16:02
-
1
-
\$\begingroup\$ @Grimy Ah ok, that makes sense. :) \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2019年05月07日 16:13:02 +00:00Commented May 7, 2019 at 16:13
Haskell, 107 bytes
let i=map(uncurry(-))$zip(tail x)(init x)in head$filter(\s->take(length i)(concat$repeat s)==i)(tail$inits i)
x is the input array.
-
\$\begingroup\$ Welcome to PPCG and Haskell golfing in particular! You cannot assume the input to be present in a certain variable, though this is easily fixed by prepending
f x=. Also the use ofinitsrequiresimport Data.List, as it is not part of Prelude: Try it online! \$\endgroup\$Laikoni– Laikoni2018年06月06日 16:24:14 +00:00Commented Jun 6, 2018 at 16:24 -
\$\begingroup\$ However you can save quite a few bytes:
(init x)can just bexbecauseziptruncates automatically if one of the lists is longer than the other one. And formap(uncurry(-))$zipexists an build-in:zipWith(-). Instead off x=let i=...inyou can use a pattern guard:f x|i<-...=. \$\endgroup\$Laikoni– Laikoni2018年06月06日 16:31:02 +00:00Commented Jun 6, 2018 at 16:31 -
\$\begingroup\$ Furthermore you can use a list comprehension instead of
filter,!!0instead ofheadandcycleinstead ofconcat$repeat: Try it online! \$\endgroup\$Laikoni– Laikoni2018年06月06日 17:43:46 +00:00Commented Jun 6, 2018 at 17:43 -
\$\begingroup\$ @Laikoni Thanks a lot for your improvements! You are right, my code needs a function declaration and an import for Data.List.inits. But I was wondering, should that be added to the length of the code? I'm asking because some of the other code samples rely on some extra code as well. \$\endgroup\$misja111– misja1112018年06月07日 18:09:49 +00:00Commented Jun 7, 2018 at 18:09
-
\$\begingroup\$ Yes, it is general consensus that those bytes are included in the score. We have a guide to golfing rules in Haskell which covers most of these cases. \$\endgroup\$Laikoni– Laikoni2018年06月07日 18:38:49 +00:00Commented Jun 7, 2018 at 18:38
Stax, (削除) 8 (削除ここまで) 6 bytes
░»F\☺»
Here's an unpacked annotated version to show how it works.
:- pairwise differences
:( all leftward rotations of array
u keep only unique rotations
mh output the first element from each unique rotation
Perl 6, 57 bytes
{~(.rotor(2=>-1).map:{.[1]-.[0]})~~/^(.+?){}" 0ドル"+$/;~0ドル}
Output is space separated ("1 1 2")
Expanded:
{ # bare block lambda with implicit parameter $_
~( # stringify (space separated)
.rotor( 2 => -1 ) # from the input take 2 backup 1, repeat
.map: { .[1] - .[0] } # subtract each pair to find the differences
)
~~ # smartmatch
/ # regex
^ # beginning of string
( .+? ) # match at least one character, but as few as possible
{} # make sure 0ドル is set (probably a compiler bug)
" 0ドル"+ # match 0ドル one or more times (with a leading space)
$ # end of string
/;
~0ドル # return the stringified 0ドル
}
-
\$\begingroup\$ The whole first part can be
~(.skip Z-$_)\$\endgroup\$Jo King– Jo King2019年05月08日 04:30:22 +00:00Commented May 8, 2019 at 4:30
05AB1E, 9 bytes
\©η.ΔÞ®Å?
Explanation:
# take input implicitly
\ # deltas, eg [4, 5, 7, 8, 10] -> [1, 2, 1, 2]
© # save this to the global register
η # prefixes, eg [1, 2, 1, 2] -> [[1], [1, 2], ...]
.Δ # find the first one such that
Þ # cycled infinitely, eg [1, 2] -> [1, 2, 1, 2, ...]
Å? # starts with
® # the global register
# and implicitly print the found element
Alternative 9-byte:
\η.ΔÞ.\-Ë
Same algo, but instead of comparing to the list of deltas (which needs to be saved/restored), this uses .\ (undelta) then compares to the (implicit) input.
K4, 30 bytes
Solution:
(*&d~/:c#'(!c:#d)#\:d)#d:1_-':
Examples:
q)k)(*&d~/:c#'(!c:#d)#\:d)#d:1_-':2, 5, 6, 7, 8, 11, 12, 13, 14, 17, 18, 19, 20
3 1 1 1
q)k)(*&d~/:c#'(!c:#d)#\:d)#d:1_-':1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17
1 1 2
q)k)(*&d~/:c#'(!c:#d)#\:d)#d:1_-':1, 4, 8, 9, 10, 13, 17, 18, 19, 22, 26, 27, 28
3 4 1 1
q)k)(*&d~/:c#'(!c:#d)#\:d)#d:1_-':6, 11, 13, 18, 20, 25, 27, 32, 34, 39, 41
5 2
q)k)(*&d~/:c#'(!c:#d)#\:d)#d:1_-':2, 6, 10, 13, 17, 21, 25, 28, 32, 36, 40, 43, 47
4 4 3 4
q)k)(*&d~/:c#'(!c:#d)#\:d)#d:1_-':5 6 7
,1
Explanation:
Seems hefty for what we're trying to solve. Get the deltas of the input and then build sequences and determine the shortest one that matches it.
(*&d~/:c#'(!c:#d)#\:d)#d:1_-': / the solution
-': / deltas
1_ / drop first
d: / save as d
# / take (#) from
( ) / do this together
#\:d / take (#) each-left (\:) from d
( ) / do this together
#d / count length of d
c: / save as c
! / range 0..c-1
c#' / take c copies of each
d~/: / d equal (~) to each right (/:)
& / where true
* / first one