Inventory sequence: Difference between revisions
(Created Nim solution.) |
(→{{header|Quackery}}: refactored) |
||
(11 intermediate revisions by 7 users not shown) | |||
Line 27: | Line 27: | ||
=={{header|ALGOL 68}}== |
|||
Calculates the sequence elements without storing them. |
|||
<syntaxhighlight lang="algol68"> |
|||
BEGIN # find elements of the inventory sequence # |
|||
INT next to show := 1 000; # next value to show first element > # |
|||
INT max to show = 10 000; # last value to show first element > # |
|||
INT max number = max to show + 1 000; # max. element value to consider # |
|||
[ 0 : max number ]INT occurs; # number of times each number occurs # |
|||
FOR i FROM LWB occurs TO UPB occurs DO occurs[ i ] := 0 OD; |
|||
INT seq pos := 0; # current end of the sequence # |
|||
WHILE next to show <= max to show DO |
|||
FOR n FROM 0 WHILE next to show <= max to show |
|||
AND BEGIN |
|||
INT element := occurs[ n ]; |
|||
seq pos +:= 1; |
|||
IF seq pos <= 100 THEN |
|||
print( ( " ", whole( element, -4 ) ) ); |
|||
IF seq pos MOD 10 = 0 THEN print( ( newline ) ) FI |
|||
ELIF element > next to show THEN |
|||
print( ( "Element ", whole( seq pos, -8 ) |
|||
, " (", whole( element, -8 ) |
|||
, ") is first > ", whole( next to show, -6 ) |
|||
, newline |
|||
) |
|||
); |
|||
next to show +:= 1 000 |
|||
FI; |
|||
IF element < max number THEN |
|||
occurs[ element ] +:= 1 |
|||
FI; |
|||
element /= 0 |
|||
END |
|||
DO SKIP OD |
|||
OD |
|||
END |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
0 1 1 0 2 2 2 0 3 2 |
|||
4 1 1 0 4 4 4 1 4 0 |
|||
5 5 4 1 6 2 1 0 6 7 |
|||
5 1 6 3 3 1 0 7 9 5 |
|||
3 6 4 4 2 0 8 9 6 4 |
|||
9 4 5 2 1 3 0 9 10 7 |
|||
5 10 6 6 3 1 4 2 0 10 |
|||
11 8 6 11 6 9 3 2 5 3 |
|||
2 0 11 11 10 8 11 7 9 4 |
|||
3 6 4 5 0 12 11 10 9 13 |
|||
Element 24256 ( 1001) is first > 1000 |
|||
Element 43302 ( 2009) is first > 2000 |
|||
Element 61709 ( 3001) is first > 3000 |
|||
Element 81457 ( 4003) is first > 4000 |
|||
Element 98705 ( 5021) is first > 5000 |
|||
Element 121343 ( 6009) is first > 6000 |
|||
Element 151757 ( 7035) is first > 7000 |
|||
Element 168805 ( 8036) is first > 8000 |
|||
Element 184429 ( 9014) is first > 9000 |
|||
Element 201789 ( 10007) is first > 10000 |
|||
</pre> |
|||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
Line 231: | Line 294: | ||
</syntaxhighlight>{{out}} Similar to Python output. |
</syntaxhighlight>{{out}} Similar to Python output. |
||
[[File:Inventory Sequence (julia).svg.svg|thumb|center]] |
[[File:Inventory Sequence (julia).svg.svg|thumb|center]] |
||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="Mathematica"> |
|||
(*Function to generate the inventory sequence*) |
|||
InventorySequence[terms_] := |
|||
Module[{num = 0, alst = {0}, inventory, c}, inventory = <|0 -> 1|>; |
|||
Table[c = Lookup[inventory, num, 0]; |
|||
num = If[c == 0, 0, num + 1]; |
|||
alst = Append[alst, c]; |
|||
inventory[c] = Lookup[inventory, c, 0] + 1;, {n, 2, terms}]; |
|||
alst] |
|||
(*Generate the inventory sequence*) |
|||
biglist = InventorySequence[201790]; |
|||
(*Print first 100 elements of the sequence*) |
|||
partitioned = Partition[Take[biglist, 100], 10]; |
|||
Do[Print[Row[partitioned[[i]], " "]], {i, Length[partitioned]}] |
|||
(*Find and print the first occurrences of elements>=thresholds*) |
|||
thresholds = 1000 Range[1, 10]; |
|||
firstOccurrences = |
|||
Reap[Do[If[biglist[[i]] >= thresholds[[1]], |
|||
Sow[{thresholds[[1]], biglist[[i]], i}]; |
|||
thresholds = Rest[thresholds]; |
|||
If[Length[thresholds] == 0, Break[]];], {i, Length[biglist]}]][[ |
|||
2, 1]]; |
|||
(*Print the formatted results*) |
|||
Do[Print["First element \[GreaterEqual] ", firstOccurrence[[1]], |
|||
" is ", firstOccurrence[[2]], " at index ", |
|||
firstOccurrence[[3]]], {firstOccurrence, firstOccurrences}] |
|||
(*Plot the first 10,000 elements of the sequence*) |
|||
ListPlot[biglist[[1 ;; 10000]], Joined -> True, |
|||
PlotStyle -> {Thin, Blue}, PlotRange -> Full] |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
0 1 1 0 2 2 2 0 3 2 |
|||
4 1 1 0 4 4 4 1 4 0 |
|||
5 5 4 1 6 2 1 0 6 7 |
|||
5 1 6 3 3 1 0 7 9 5 |
|||
3 6 4 4 2 0 8 9 6 4 |
|||
9 4 5 2 1 3 0 9 10 7 |
|||
5 10 6 6 3 1 4 2 0 10 |
|||
11 8 6 11 6 9 3 2 5 3 |
|||
2 0 11 11 10 8 11 7 9 4 |
|||
3 6 4 5 0 12 11 10 9 13 |
|||
First element >= 1000 is 1001 at index 24256 |
|||
First element >= 2000 is 2009 at index 43302 |
|||
First element >= 3000 is 3001 at index 61709 |
|||
First element >= 4000 is 4003 at index 81457 |
|||
First element >= 5000 is 5021 at index 98705 |
|||
First element >= 6000 is 6009 at index 121343 |
|||
First element >= 7000 is 7035 at index 151757 |
|||
First element >= 8000 is 8036 at index 168805 |
|||
First element >= 9000 is 9014 at index 184429 |
|||
First element >= 10000 is 10007 at index 201789 |
|||
</pre> |
|||
[[File:Plot the first 10, 000 elements of the inventory sequence.svg|thumb|center]] |
|||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
Line 296: | Line 423: | ||
</pre> |
</pre> |
||
[[File:Inventory Sequence (Nim).png|thumb|center]] |
[[File:Inventory Sequence (Nim).png|thumb|center]] |
||
=={{header|Perl}}== |
|||
{{libheader|ntheory}} |
|||
{{trans|Raku}} |
|||
<syntaxhighlight lang="perl" line> |
|||
use strict; |
|||
use warnings; |
|||
use feature 'say'; |
|||
use List::AllUtils <max firstidx>; |
|||
use GD::Graph::bars; |
|||
sub comma { reverse ((reverse shift) =~ s/.{3}\K/,/gr) =~ s/^,//r } |
|||
sub table { my $t = 20 * (my $c = 1 + length max @_); ( sprintf( ('%'.$c.'d')x@_, @_) ) =~ s/.{1,$t}\K/\n/gr } |
|||
my($i, @inventory, %i) = 0; |
|||
do { |
|||
my $count = $i{$i} // 0; |
|||
$i = $count ? $i+1 : 0; |
|||
++$i{$count}; |
|||
push @inventory, $count |
|||
} until $inventory[-1] > 10_000; |
|||
say "Inventory sequence, first 100 elements:\n" . table @inventory[0..99]; say ''; |
|||
for my $n (map { $_ * 1000 } 1..10) { |
|||
my $i = firstidx { $_ >= $n } @inventory; |
|||
printf "First element >= %6s is %6s in position: %s\n", comma($n), comma($inventory[$i]), comma $i; |
|||
} |
|||
# graph |
|||
my @data = ( [0..5000], [@inventory[0..5000]] ); |
|||
my $graph = GD::Graph::bars->new(800, 600); |
|||
$graph->set( |
|||
title => 'Inventory sequence', |
|||
y_max_value => 250, |
|||
x_tick_number => 5, |
|||
r_margin => 10, |
|||
dclrs => [ 'blue' ], |
|||
) or die $graph->error; |
|||
my $gd = $graph->plot(\@data) or die $graph->error; |
|||
open my $fh, '>', 'Perl-inventory-sequence.png'; |
|||
binmode $fh; |
|||
print $fh $gd->png(); |
|||
close $fh; |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Inventory sequence, first 100 elements: |
|||
0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 |
|||
5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 |
|||
3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 |
|||
5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 |
|||
2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 |
|||
First element >= 1,000 is 1,001 in position: 24,255 |
|||
First element >= 2,000 is 2,009 in position: 43,301 |
|||
First element >= 3,000 is 3,001 in position: 61,708 |
|||
First element >= 4,000 is 4,003 in position: 81,456 |
|||
First element >= 5,000 is 5,021 in position: 98,704 |
|||
First element >= 6,000 is 6,009 in position: 121,342 |
|||
First element >= 7,000 is 7,035 in position: 151,756 |
|||
First element >= 8,000 is 8,036 in position: 168,804 |
|||
First element >= 9,000 is 9,014 in position: 184,428 |
|||
First element >= 10,000 is 10,007 in position: 201,788 |
|||
</pre> |
|||
[[File:Perl-inventory-sequence.png|thumb|center]] |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Line 396: | Line 591: | ||
plot(biglist[:10_000], linewidth=0.3) |
plot(biglist[:10_000], linewidth=0.3) |
||
plt.show() |
|||
</syntaxhighlight>{{out}} |
</syntaxhighlight>{{out}} |
||
<pre> |
<pre> |
||
Line 425: | Line 621: | ||
</pre> |
</pre> |
||
[[File:Inventory Sequence.png|500px|thumb|center]] |
[[File:Inventory Sequence.png|500px|thumb|center]] |
||
=={{header|Quackery}}== |
|||
<syntaxhighlight lang="Quackery"> [ 0 unrot witheach |
|||
[ over = |
|||
rot + swap ] |
|||
drop ] is occurs ( n [ --> n ) |
|||
[ 2dup occurs |
|||
tuck join |
|||
dip [ 0 != tuck * + ] ] is additem ( n [ --> n [ ) |
|||
0 [] 100 times additem |
|||
witheach |
|||
[ dup 10 < if sp |
|||
echo sp |
|||
i^ 10 mod 9 = if cr ] |
|||
drop |
|||
cr |
|||
0 [] |
|||
[ additem |
|||
dup -1 peek 999 > |
|||
until ] |
|||
say "Element #" |
|||
dup size 1 - echo |
|||
say " is " |
|||
-1 peek echo |
|||
say "." cr |
|||
drop</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 0 1 1 0 2 2 2 0 3 2 |
|||
4 1 1 0 4 4 4 1 4 0 |
|||
5 5 4 1 6 2 1 0 6 7 |
|||
5 1 6 3 3 1 0 7 9 5 |
|||
3 6 4 4 2 0 8 9 6 4 |
|||
9 4 5 2 1 3 0 9 10 7 |
|||
5 10 6 6 3 1 4 2 0 10 |
|||
11 8 6 11 6 9 3 2 5 3 |
|||
2 0 11 11 10 8 11 7 9 4 |
|||
3 6 4 5 0 12 11 10 9 13 |
|||
Element #24255 is 1001.</pre> |
|||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
Line 488: | Line 728: | ||
[[File:Inventory-raku.png|400px|thumb|left|]] |
[[File:Inventory-raku.png|400px|thumb|left|]] |
||
<br clear=all> |
<br clear=all> |
||
=={{header|RPL}}== |
|||
For efficiency reasons, two different programs are needed to generate the sequence or search for the first high value. |
|||
« → max |
|||
« { 0 1 1 0 } <span style="color:grey">@ need to start with a non-null cycle to have ∑LIST work</span> |
|||
'''WHILE''' DUP SIZE max < '''REPEAT''' |
|||
0 max '''FOR''' j |
|||
DUP 1 « j == » DOLIST ∑LIST <span style="color:grey">@ count occurrences in the list</span> |
|||
'''IF''' DUP NOT '''THEN''' max 'j' STO '''END''' |
|||
+ |
|||
'''NEXT''' |
|||
'''END''' |
|||
1 max SUB |
|||
» '<span style="color:blue">INVT</span>' STO <span style="color:grey">@ ''( n → { a(1)..a(n)} )''</span> |
|||
« DUP 1 + { } + 0 CON -1 → max counts j |
|||
« 2 CF 1 |
|||
'''DO''' 'counts' 'j' INCR 1 + |
|||
'''IFERR''' GET THEN DROP2 0 '''END''' |
|||
'''IF''' DUP NOT THEN -1 'j' STO '''END''' |
|||
'''IF''' DUP max > '''THEN''' |
|||
"element" →TAG SWAP "position" →TAG 2 SF |
|||
'''ELSE''' |
|||
'counts' SWAP 1 + DUP2 GET 1 + PUT 1 + |
|||
'''END''' |
|||
'''UNTIL''' 2 FS? '''END''' |
|||
» » '<span style="color:blue">INVT1ST</span>' STO <span style="color:grey">@ ''( n → 1st_value_>_n pos )''</span> |
|||
100 <span style="color:blue">INVT</span> |
|||
1000 <span style="color:blue">INVT1ST</span> |
|||
{{out}} |
|||
<pre> |
|||
3: { 0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 } |
|||
2: element: 1001 |
|||
1: position: 24256 |
|||
</pre> |
|||
=={{header|Ruby}}== |
|||
Not actually counting but keeping count in a hash: |
|||
<syntaxhighlight lang="ruby" line>n = 0 |
|||
counter = Hash.new(0) |
|||
inventory = loop.lazy.map do |
|||
c = counter[n] |
|||
counter[c] += 1 |
|||
c == 0 ? n = 0 : n += 1 |
|||
c |
|||
end |
|||
inventory.first(100).each_slice(10){|s| puts "%4d"*s.size % s} |
|||
puts |
|||
(1000..10000).step(1000).each do |t| |
|||
counter.clear |
|||
puts "First element >= #{t} : %d index %d" % inventory.with_index.detect{|e,i| e > t} |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 0 1 1 0 2 2 2 0 3 2 |
|||
4 1 1 0 4 4 4 1 4 0 |
|||
5 5 4 1 6 2 1 0 6 7 |
|||
5 1 6 3 3 1 0 7 9 5 |
|||
3 6 4 4 2 0 8 9 6 4 |
|||
9 4 5 2 1 3 0 9 10 7 |
|||
5 10 6 6 3 1 4 2 0 10 |
|||
11 8 6 11 6 9 3 2 5 3 |
|||
2 0 11 11 10 8 11 7 9 4 |
|||
3 6 4 5 0 12 11 10 9 13 |
|||
First element >= 1000 : 1001 index 24255 |
|||
First element >= 2000 : 2009 index 43301 |
|||
First element >= 3000 : 3001 index 61708 |
|||
First element >= 4000 : 4003 index 81456 |
|||
First element >= 5000 : 5021 index 98704 |
|||
First element >= 6000 : 6009 index 121342 |
|||
First element >= 7000 : 7035 index 151756 |
|||
First element >= 8000 : 8036 index 168804 |
|||
First element >= 9000 : 9014 index 184428 |
|||
First element >= 10000 : 10007 index 201788 |
|||
</pre> |
|||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
{{libheader|DOME}} |
{{libheader|DOME}} |
||
Line 493: | Line 811: | ||
{{libheader|Wren-iterate}} |
{{libheader|Wren-iterate}} |
||
{{libheader|Wren-fmt}} |
{{libheader|Wren-fmt}} |
||
<syntaxhighlight lang=" |
<syntaxhighlight lang="wren">import "dome" for Window |
||
import "graphics" for Canvas, Color |
import "graphics" for Canvas, Color |
||
import "./plot" for Axes |
import "./plot" for Axes |
Latest revision as of 09:19, 20 June 2024
To build the inventory sequence, first take inventory of what numbers are already in the sequence, then, starting with 0 add the count of each number in turn to the end of the sequence. When you reach a number that has a count of 0, stop, add the 0 to the end of the sequence, and then restart the inventory from 0.
- E.G.
- Start taking inventory; how many 0s are there? 0. Add a 0 to the end of the sequence and restart the inventory. (0)
- How many 0s are there? 1. Add a 1 to the end of the sequence. How many 1s are there? 1. Add a 1 to the end of the sequence. How many 2s are there? 0. Add a 0 to the end of the sequence and restart the inventory. (0 1 1 0)
- and so on.
- Task
- Find and display the first 100 elements of the sequence.
- Find and display the position and value of the first element greater than or equal to 1000.
- Stretch
- Find and display the position and value of the first element greater than or equal to 2000, 3000 ... 10,000.
- Plot a graph of the first 10,000 elements of the sequence.
- See also
ALGOL 68
Calculates the sequence elements without storing them.
BEGIN # find elements of the inventory sequence #
INT next to show := 1 000; # next value to show first element > #
INT max to show = 10 000; # last value to show first element > #
INT max number = max to show + 1 000; # max. element value to consider #
[ 0 : max number ]INT occurs; # number of times each number occurs #
FOR i FROM LWB occurs TO UPB occurs DO occurs[ i ] := 0 OD;
INT seq pos := 0; # current end of the sequence #
WHILE next to show <= max to show DO
FOR n FROM 0 WHILE next to show <= max to show
AND BEGIN
INT element := occurs[ n ];
seq pos +:= 1;
IF seq pos <= 100 THEN
print( ( " ", whole( element, -4 ) ) );
IF seq pos MOD 10 = 0 THEN print( ( newline ) ) FI
ELIF element > next to show THEN
print( ( "Element ", whole( seq pos, -8 )
, " (", whole( element, -8 )
, ") is first > ", whole( next to show, -6 )
, newline
)
);
next to show +:= 1 000
FI;
IF element < max number THEN
occurs[ element ] +:= 1
FI;
element /= 0
END
DO SKIP OD
OD
END
- Output:
0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 Element 24256 ( 1001) is first > 1000 Element 43302 ( 2009) is first > 2000 Element 61709 ( 3001) is first > 3000 Element 81457 ( 4003) is first > 4000 Element 98705 ( 5021) is first > 5000 Element 121343 ( 6009) is first > 6000 Element 151757 ( 7035) is first > 7000 Element 168805 ( 8036) is first > 8000 Element 184429 ( 9014) is first > 9000 Element 201789 ( 10007) is first > 10000
FreeBASIC
Dim As Integer max = 10000
Dim As Integer inv()
Dim As Integer counts(max + 100)
counts(0) = 1
Dim As Integer lower = 100
Dim As Integer upper = 1000
Dim As Boolean done = False
Dim As Integer ix = 0
While Not done
Dim As Integer i = 0, c = 0
Do
Dim As Integer j = counts(i)
If Ubound(inv) < max Then
Redim Preserve inv(ix+1)
inv(ix+1) = j
End If
counts(j) += 1
ix += 1
If Ubound(inv) >= lower Then
Print "Inventory sequence, first 100 elements:"
For c = 0 To 99
Print Using "###"; inv(c);
If (c+1) Mod 20 = 0 Then Print
Next
lower = max + 1
End If
If j = 0 Then Exit Do
If j >= upper Then
Print Using !"\nFirst element >= ##,### is ##,### at index ###,###"; upper; j; ix;
If j >= max Then done = True: Exit Do
upper += 1000
End If
i += 1
Loop
Wend
Sleep
J
nextinv=: ((*@] * 1+{.@[), }.@[ , ]) +/@({. = }.)
10 10$}.nextinv^:100]0 NB. first 100 elements of inventory sequence
0 1 1 0 2 2 2 0 3 2
4 1 1 0 4 4 4 1 4 0
5 5 4 1 6 2 1 0 6 7
5 1 6 3 3 1 0 7 9 5
3 6 4 4 2 0 8 9 6 4
9 4 5 2 1 3 0 9 10 7
5 10 6 6 3 1 4 2 0 10
11 8 6 11 6 9 3 2 5 3
2 0 11 11 10 8 11 7 9 4
3 6 4 5 0 12 11 10 9 13
({:,_2+#)nextinv^:(1000>{:)^:_]0 NB. first value of at least 1000 and its index
1001 24255
The inventory sequence has a "hidden value" which is the number that we are searching for, and counting. So, here, we include it as the first element of the representation of an inventory subsequence. And nextinv
calculates both the next "hidden value" as well as the corresponding subsequence which incorporates a count of how many times the current "hidden value" appeared.
For the task, we iterate inductively from the initial state (either a 100 times or until we find a value which is greater than 1000).
It would be more efficient to maintain counts of each integer so far encountered, but that efficiency is not necessary for this task (and would require more code).
That said, here's a faster implementation:
invseq=: {{
cnt=. 0, seq=. i. nxt=. 0
while. -. u seq do.
k=. nxt{cnt
nxt=. (*k)*nxt+1
cnt=. (1+k{cnt) k} cnt=. cnt {.~ (2+k)>.#cnt
seq=. seq, k
end.
}}
stretch=: }.nextinv^:(10000>{:)^:_]0 NB. or
stretch=: (1e4<:{:) invseq NB. equivalent, faster approach
(,~ {&stretch) {.I.2000<stretch NB. first value greater than 2000 and its index
2009 43301
(,~ {&stretch) {.I.3000<stretch
3001 61708
(,~ {&stretch) {.I.4000<stretch
4003 81456
(,~ {&stretch) {.I.5000<stretch
5021 98704
(,~ {&stretch) {.I.6000<stretch
6009 121342
(,~ {&stretch) {.I.7000<stretch
7035 151756
(,~ {&stretch) {.I.8000<stretch
8036 168804
(,~ {&stretch) {.I.9000<stretch
9014 184428
(,~ {&stretch) {.I.10000<stretch
10007 201788
require'plot'
plot 1e4{.stretch
jq
Works with both jq and gojq, the C and Go implementations of jq
... but note that gojq takes about 5 times longer (and requires much more memory) to complete the task.
With minor modifications, the program below also works quite snappily with jaq, the Rust implementation of jq.
The definition of `_nwise` can be omitted if using the C implementation of jq.
def _nwise($n):
def n: if length <= $n then . else .[0:$n] , (.[$n:] | n) end;
n;
# Emit the inventory sequence ad infinitum
def inventory_sequence:
{num: 0,
emit: 0,
inventory: {} }
| foreach range(0; infinite) as $n (.;
.emit = (.inventory[.num|tostring] // 0)
| if .emit == 0 then .num = 0 else .num += 1 end
| .inventory[.emit|tostring] += 1 )
| .emit ;
# Report on the progress of an arbitrary sequence, indefinitely
# Emit [.next, $x, .n]
def probe(s; $gap):
foreach s as $x ({n: 0, next: $gap};
.n += 1
| if $x >= .next then .emit = {next, $x, n} | .next += $gap
else .emit = null
end)
| select(.emit).emit;
def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;
def task($n):
[limit($n; inventory_sequence)] | _nwise(10) | map(lpad(3)) | join(" ");
task(100),
"",
(limit(10; probe(inventory_sequence; 1000))
| "First element >= \(.next) is \(.x) at index \(.n - 1)")
- Output:
0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1000 is 1001 at index 24255 First element >= 2000 is 2009 at index 43301 First element >= 3000 is 3001 at index 61708 First element >= 4000 is 4003 at index 81456 First element >= 5000 is 5021 at index 98704 First element >= 6000 is 6009 at index 121342 First element >= 7000 is 7035 at index 151756 First element >= 8000 is 8036 at index 168804 First element >= 9000 is 9014 at index 184428 First element >= 10000 is 10007 at index 201788
Julia
""" rosettacode.org/wiki/Inventory_sequence """
using Printf
using Counters
using Plots
struct InventorySequence
inventory::Counter{Int}
InventorySequence() = new(counter([0]))
end
function Base.iterate(i::InventorySequence, num = 0)
nextval = i.inventory[num]
num = nextval == 0 ? 0 : num + 1
i.inventory[nextval] += 1
return nextval, num
end
const thresholds = [1000 * j for j in 1:10]
const toplot = Int[]
for (i, n) in enumerate(InventorySequence())
if i <= 100
print(rpad(n, 4), i % 20 == 0 ? "\n" : "")
elseif n >= thresholds[begin]
@printf("First element >= %d5: %d5 in position %d.\n", popfirst!(thresholds), n, i)
length(thresholds) == 0 && break
end
length(toplot) < 10000 && push!(toplot, n)
end
plot(toplot)
- Output:
Similar to Python output.
Mathematica/Wolfram Language
(*Function to generate the inventory sequence*)
InventorySequence[terms_] :=
Module[{num = 0, alst = {0}, inventory, c}, inventory = <|0 -> 1|>;
Table[c = Lookup[inventory, num, 0];
num = If[c == 0, 0, num + 1];
alst = Append[alst, c];
inventory[c] = Lookup[inventory, c, 0] + 1;, {n, 2, terms}];
alst]
(*Generate the inventory sequence*)
biglist = InventorySequence[201790];
(*Print first 100 elements of the sequence*)
partitioned = Partition[Take[biglist, 100], 10];
Do[Print[Row[partitioned[[i]], " "]], {i, Length[partitioned]}]
(*Find and print the first occurrences of elements>=thresholds*)
thresholds = 1000 Range[1, 10];
firstOccurrences =
Reap[Do[If[biglist[[i]] >= thresholds[[1]],
Sow[{thresholds[[1]], biglist[[i]], i}];
thresholds = Rest[thresholds];
If[Length[thresholds] == 0, Break[]];], {i, Length[biglist]}]][[
2, 1]];
(*Print the formatted results*)
Do[Print["First element \[GreaterEqual] ", firstOccurrence[[1]],
" is ", firstOccurrence[[2]], " at index ",
firstOccurrence[[3]]], {firstOccurrence, firstOccurrences}]
(*Plot the first 10,000 elements of the sequence*)
ListPlot[biglist[[1 ;; 10000]], Joined -> True,
PlotStyle -> {Thin, Blue}, PlotRange -> Full]
- Output:
0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1000 is 1001 at index 24256 First element >= 2000 is 2009 at index 43302 First element >= 3000 is 3001 at index 61709 First element >= 4000 is 4003 at index 81457 First element >= 5000 is 5021 at index 98705 First element >= 6000 is 6009 at index 121343 First element >= 7000 is 7035 at index 151757 First element >= 8000 is 8036 at index 168805 First element >= 9000 is 9014 at index 184429 First element >= 10000 is 10007 at index 201789
Nim
import std/[strformat, tables]
import gnuplot
iterator inventorySequence(): (int, int) =
var counts: CountTable[int]
var idx = -1
while true:
var i = 0
while true:
let n = counts[i]
inc idx
counts.inc(n)
yield (idx, n)
if n == 0: break
inc i
echo "First 100 elements:"
var x, y: seq[int]
var lim = 1000
for idx, n in inventorySequence():
if idx < 10000:
x.add idx
y.add n
if idx <= 100:
stdout.write &"{n:>2}"
stdout.write if idx mod 10 == 0: '\n' else: ' '
if idx == 100: echo()
elif n >= lim:
echo &"First element ⩾ {lim:>5} is {n:>5} at index {idx:>6}"
lim += 1000
if lim > 10000: break
withGnuPlot:
plot(x, y, "Inventory sequence", "with impulses lw 0.5")
png("inventory_sequence.png")
- Output:
First 100 elements: 0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 8 First element ⩾ 1000 is 1001 at index 24255 First element ⩾ 2000 is 2009 at index 43301 First element ⩾ 3000 is 3001 at index 61708 First element ⩾ 4000 is 4003 at index 81456 First element ⩾ 5000 is 5021 at index 98704 First element ⩾ 6000 is 6009 at index 121342 First element ⩾ 7000 is 7035 at index 151756 First element ⩾ 8000 is 8036 at index 168804 First element ⩾ 9000 is 9014 at index 184428 First element ⩾ 10000 is 10007 at index 201788
Perl
use strict;
use warnings;
use feature 'say';
use List::AllUtils <max firstidx>;
use GD::Graph::bars;
sub comma { reverse ((reverse shift) =~ s/.{3}\K/,/gr) =~ s/^,//r }
sub table { my $t = 20 * (my $c = 1 + length max @_); ( sprintf( ('%'.$c.'d')x@_, @_) ) =~ s/.{1,$t}\K/\n/gr }
my($i, @inventory, %i) = 0;
do {
my $count = $i{$i} // 0;
$i = $count ? $i+1 : 0;
++$i{$count};
push @inventory, $count
} until $inventory[-1] > 10_000;
say "Inventory sequence, first 100 elements:\n" . table @inventory[0..99]; say '';
for my $n (map { $_ * 1000 } 1..10) {
my $i = firstidx { $_ >= $n } @inventory;
printf "First element >= %6s is %6s in position: %s\n", comma($n), comma($inventory[$i]), comma $i;
}
# graph
my @data = ( [0..5000], [@inventory[0..5000]] );
my $graph = GD::Graph::bars->new(800, 600);
$graph->set(
title => 'Inventory sequence',
y_max_value => 250,
x_tick_number => 5,
r_margin => 10,
dclrs => [ 'blue' ],
) or die $graph->error;
my $gd = $graph->plot(\@data) or die $graph->error;
open my $fh, '>', 'Perl-inventory-sequence.png';
binmode $fh;
print $fh $gd->png();
close $fh;
- Output:
Inventory sequence, first 100 elements: 0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1,000 is 1,001 in position: 24,255 First element >= 2,000 is 2,009 in position: 43,301 First element >= 3,000 is 3,001 in position: 61,708 First element >= 4,000 is 4,003 in position: 81,456 First element >= 5,000 is 5,021 in position: 98,704 First element >= 6,000 is 6,009 in position: 121,342 First element >= 7,000 is 7,035 in position: 151,756 First element >= 8,000 is 8,036 in position: 168,804 First element >= 9,000 is 9,014 in position: 184,428 First element >= 10,000 is 10,007 in position: 201,788
Phix
-- demo\rosetta\Inventory_sequence.exw with javascript_semantics function inventory(integer limit) sequence inv = {0}, counts = {1} integer ix = 0, thousands = 1000 while true do integer i = 0 while true do integer j = iff(i>=length(counts)?0:counts[i+1]) inv &= j while j>=length(counts) do counts &= 0 end while counts[j+1] += 1 ix += 1 if length(inv)=100 then printf(1,"Inventory sequence, first 100 elements:\n%s\n", {join_by(inv,1,20,"",fmt:="%3d")}) end if if j=0 then exit end if if j>=thousands then printf(1,"First element >= %,6d is %,6d at index %,7d\n", {thousands, j, ix}) if j>=limit then return inv[1..limit] end if thousands += 1000 end if i += 1 end while end while end function constant lim = 1e4 sequence x = tagset(lim), y = inventory(lim) include pGUI.e include IupGraph.e function get_data(Ihandle graph) integer {w,h} = IupGetIntInt(graph,"SIZE") IupSetInt(graph,"XTICK",iff(w<500?iff(w<350?iff(w<250?5000:2500):2000):1000)) IupSetInt(graph,"YTICK",iff(h<350?iff(h<200?iff(h<150? 200: 100): 80): 40)) return {{x,y,CD_BLUE}} end function IupOpen() Ihandle graph = IupGraph(get_data,"XMIN=0,XMAX=10000,YMIN=0,YMAX=400"), dlg = IupDialog(graph,`TITLE=gGraph,SIZE=320x240,MINSIZE=240x140`) IupShow(dlg) if platform()!=JS then IupMainLoop() end if
- Output:
Inventory sequence, first 100 elements: 0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1,000 is 1,001 at index 24,255 First element >= 2,000 is 2,009 at index 43,301 First element >= 3,000 is 3,001 at index 61,708 First element >= 4,000 is 4,003 at index 81,456 First element >= 5,000 is 5,021 at index 98,704 First element >= 6,000 is 6,009 at index 121,342 First element >= 7,000 is 7,035 at index 151,756 First element >= 8,000 is 8,036 at index 168,804 First element >= 9,000 is 9,014 at index 184,428 First element >= 10,000 is 10,007 at index 201,788
Python
''' rosettacode.org/wiki/Inventory_sequence '''
from collections import Counter
from matplotlib.pyplot import plot
def inventory_sequence(terms):
''' From the code by Branicky at oeis.org/A342585 '''
num, alst, inventory = 0, [0], Counter([0])
for n in range(2, terms+1):
c = inventory[num]
num = 0 if c == 0 else num + 1
alst.append(c)
inventory.update([c])
return alst
biglist = inventory_sequence(201_790)
thresholds = [1000 * j for j in range(1, 11)]
for i, k in enumerate(biglist):
if i < 100:
print(f'{k:<4}', end='\n' if (i + 1) % 20 == 0 else '')
elif k >= thresholds[0]:
print(f'\nFirst element >= {thresholds.pop(0):5}: {k:5} in position {i:6}')
if len(thresholds) == 0:
break
plot(biglist[:10_000], linewidth=0.3)
plt.show()
- Output:
0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1000: 1001 in position 24255 First element >= 2000: 2009 in position 43301 First element >= 3000: 3001 in position 61708 First element >= 4000: 4003 in position 81456 First element >= 5000: 5021 in position 98704 First element >= 6000: 6009 in position 121342 First element >= 7000: 7035 in position 151756 First element >= 8000: 8036 in position 168804 First element >= 9000: 9014 in position 184428 First element >= 10000: 10007 in position 201788
Quackery
[ 0 unrot witheach
[ over =
rot + swap ]
drop ] is occurs ( n [ --> n )
[ 2dup occurs
tuck join
dip [ 0 != tuck * + ] ] is additem ( n [ --> n [ )
0 [] 100 times additem
witheach
[ dup 10 < if sp
echo sp
i^ 10 mod 9 = if cr ]
drop
cr
0 []
[ additem
dup -1 peek 999 >
until ]
say "Element #"
dup size 1 - echo
say " is "
-1 peek echo
say "." cr
drop
- Output:
0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 Element #24255 is 1001.
Raku
use Lingua::EN::Numbers;
my ($i, %i) = 0;
my @inventory = (^∞).map: {
my $count = %i{$i} // 0;
$i = $count ?? $i+1 !! 0;
++%i{$count};
$count
}
say "Inventory sequence, first 100 elements:\n" ~
@inventory[^100].batch(20)».fmt("%2d").join: "\n";
say '';
for (1..10).map: * × 1000 {
my $k = @inventory.first: * >= $_, :k;
printf "First element >= %6s is %6s in position: %s\n",
.&comma, @inventory[$k].&comma, comma $k;
}
use SVG;
use SVG::Plot;
my @x = ^10000;
'Inventory-raku.svg'.IO.spurt:
SVG.serialize: SVG::Plot.new(
background => 'white',
width => 1000,
height => 600,
plot-width => 950,
plot-height => 550,
x => @x,
values => [@inventory[@x],],
title => "Inventory Sequence - First {+@x} values (zero indexed)",
).plot: :lines;
- Output:
Inventory sequence, first 100 elements: 0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1,000 is 1,001 in position: 24,255 First element >= 2,000 is 2,009 in position: 43,301 First element >= 3,000 is 3,001 in position: 61,708 First element >= 4,000 is 4,003 in position: 81,456 First element >= 5,000 is 5,021 in position: 98,704 First element >= 6,000 is 6,009 in position: 121,342 First element >= 7,000 is 7,035 in position: 151,756 First element >= 8,000 is 8,036 in position: 168,804 First element >= 9,000 is 9,014 in position: 184,428 First element >= 10,000 is 10,007 in position: 201,788
converted to a .png to reduce size for display here:
RPL
For efficiency reasons, two different programs are needed to generate the sequence or search for the first high value.
« → max « { 0 1 1 0 } @ need to start with a non-null cycle to have ∑LIST work WHILE DUP SIZE max < REPEAT 0 max FOR j DUP 1 « j == » DOLIST ∑LIST @ count occurrences in the list IF DUP NOT THEN max 'j' STO END + NEXT END 1 max SUB » 'INVT' STO @ ( n → { a(1)..a(n)} ) « DUP 1 + { } + 0 CON -1 → max counts j « 2 CF 1 DO 'counts' 'j' INCR 1 + IFERR GET THEN DROP2 0 END IF DUP NOT THEN -1 'j' STO END IF DUP max > THEN "element" →TAG SWAP "position" →TAG 2 SF ELSE 'counts' SWAP 1 + DUP2 GET 1 + PUT 1 + END UNTIL 2 FS? END » » 'INVT1ST' STO @ ( n → 1st_value_>_n pos )
100 INVT 1000 INVT1ST
- Output:
3: { 0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 } 2: element: 1001 1: position: 24256
Ruby
Not actually counting but keeping count in a hash:
n = 0
counter = Hash.new(0)
inventory = loop.lazy.map do
c = counter[n]
counter[c] += 1
c == 0 ? n = 0 : n += 1
c
end
inventory.first(100).each_slice(10){|s| puts "%4d"*s.size % s}
puts
(1000..10000).step(1000).each do |t|
counter.clear
puts "First element >= #{t} : %d index %d" % inventory.with_index.detect{|e,i| e > t}
end
- Output:
0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1000 : 1001 index 24255 First element >= 2000 : 2009 index 43301 First element >= 3000 : 3001 index 61708 First element >= 4000 : 4003 index 81456 First element >= 5000 : 5021 index 98704 First element >= 6000 : 6009 index 121342 First element >= 7000 : 7035 index 151756 First element >= 8000 : 8036 index 168804 First element >= 9000 : 9014 index 184428 First element >= 10000 : 10007 index 201788
Wren
import "dome" for Window
import "graphics" for Canvas, Color
import "./plot" for Axes
import "./iterate" for Stepped
import "./fmt" for Fmt
var max = 10000
var inv = [0]
var counts = List.filled(max + 100, 0) // say
counts[0] = 1
var lower = 100
var upper = 1000
var done = false
var ix = 0
while (!done) {
var i = 0
while(true) {
var j = counts[i]
if (inv.count < max) inv.add(j)
counts[j] = counts[j] + 1
ix = ix + 1
if (inv.count >= lower) {
System.print("Inventory sequence, first 100 elements:")
Fmt.tprint("$2d", inv[0..99], 20)
System.print()
lower = max + 1
}
if (j == 0) break
if (j >= upper) {
Fmt.print("First element >= $,6d is $,6d at index $,7d", upper, j, ix)
if (j >= max) {
done = true
break
}
upper = upper + 1000
}
i = i + 1
}
}
// generate points for the plot
var Pts = (0...max).map { |i| [i, inv[i]] }.toList
class Main {
construct new() {
Window.title = "Inventory sequence - first 10,000 elements."
Canvas.resize(1000, 600)
Window.resize(1000, 600)
Canvas.cls(Color.white)
var axes = Axes.new(100, 500, 800, 400, 0..10000, 0..450)
axes.draw(Color.black, 2)
var xMarks = Stepped.new(0..10000, 500)
var yMarks = Stepped.new(0..400, 50)
axes.mark(xMarks, yMarks, Color.black, 2)
var xMarks2 = Stepped.new(0..10000, 1000)
var yMarks2 = Stepped.new(0..400, 100)
axes.label(xMarks2, yMarks2, Color.black, 2, Color.black)
axes.lineGraph(Pts, Color.blue, 2)
}
init() {}
update() {}
draw(alpha) {}
}
var Game = Main.new()
- Output:
Terminal output:
Inventory sequence, first 100 elements: 0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1,000 is 1,001 at index 24,255 First element >= 2,000 is 2,009 at index 43,301 First element >= 3,000 is 3,001 at index 61,708 First element >= 4,000 is 4,003 at index 81,456 First element >= 5,000 is 5,021 at index 98,704 First element >= 6,000 is 6,009 at index 121,342 First element >= 7,000 is 7,035 at index 151,756 First element >= 8,000 is 8,036 at index 168,804 First element >= 9,000 is 9,014 at index 184,428 First element >= 10,000 is 10,007 at index 201,788
XPL0
include xpllib; \for Print
def Size = 201_790;
int Seq(Size), SeqEnd, Num, Count, N, Thresh;
[SeqEnd:= 0;
loop [Num:= 0;
repeat Count:= 0;
for N:= 0 to SeqEnd-1 do
if Num = Seq(N) then Count:= Count+1;
Seq(SeqEnd):= Count;
SeqEnd:= SeqEnd+1;
if SeqEnd >= Size then quit;
Num:= Num+1;
until Count = 0;
];
Thresh:= 1000;
for N:= 0 to SeqEnd-1 do
if N < 100 then
[Print("%3.0f", float(Seq(N)));
if rem(N/20) = 19 then CrLf(0);
]
else if Seq(N) >= Thresh then
[Print("First element >= %5.0f: %5.0f in position %6.0f\n",
float(Thresh), float(Seq(N)), float(N));
if Thresh >= 10000 then return;
Thresh:= Thresh + 1000;
];
]
- Output:
0 1 1 0 2 2 2 0 3 2 4 1 1 0 4 4 4 1 4 0 5 5 4 1 6 2 1 0 6 7 5 1 6 3 3 1 0 7 9 5 3 6 4 4 2 0 8 9 6 4 9 4 5 2 1 3 0 9 10 7 5 10 6 6 3 1 4 2 0 10 11 8 6 11 6 9 3 2 5 3 2 0 11 11 10 8 11 7 9 4 3 6 4 5 0 12 11 10 9 13 First element >= 1000: 1001 in position 24255 First element >= 2000: 2009 in position 43301 First element >= 3000: 3001 in position 61708 First element >= 4000: 4003 in position 81456 First element >= 5000: 5021 in position 98704 First element >= 6000: 6009 in position 121342 First element >= 7000: 7035 in position 151756 First element >= 8000: 8036 in position 168804 First element >= 9000: 9014 in position 184428 First element >= 10000: 10007 in position 201788