Automate the OEIS

26

3

We see a lot of challenges here asking for a function to create a sequence from the OEIS. While these challenges are fun, as a programmer I see an opportunity for automation.

Your challenge is to make a program that takes the index of a sequence (e.g. A172141) and some integer n (e.g. 7), and pulls the appropriate value from the appropriate webpage.

I/O

As mentioned, your program should take a sequence index and some value n as input and output the nth term in that sequence. You accept any index in the sequence's B-files. If the index is greater than the largest index listed in the B-files you may throw an exception or output whatever you choose (these are not in the test cases). Standard methods of input and output are permitted.

Restrictions on web use

You should not access any websites other than https://oeis.org and http://oeis.org. This includes url shorteners, your own personal website, and this question itself. If you would like to access some other website and you believe that it is not unfair to allow you to do so, you can leave a comment and I will arbitrate.

Scoring

This is a code golf challenge so the program with the least bytes used in its source code wins. Standard loopholes are disallowed.

Test Cases

Assuming that your machine has proper internet connection and the OEIS servers are up and running the following inputs and outputs should correspond.

A172141, 7   -> 980
A173429, 4   -> 276
A190394, 6   -> 16
A002911, 11  -> 960
A052170, 3   -> 24
A060296, 8   -> 3
A178732, 5   -> 27
A000001, 1   -> 1
A000796, 314 -> 3
A001622, 162 -> 8
A002206, -1  -> 1

Tip

  • When accessing the B-files http://oeis.org/b<A-number>.txt will redirect to the proper B-file.

Post Rock Garf Hunter

Posted 2016-08-10T15:28:05.463

Reputation: 55 382

1It's not clear to me up which indices we have to support. The last two test cases hint that we should query, e.g., oeis.org/A000796/b000796.txt rather than oeis.org/A000796/list. Is the fomer what you mean by B-files? In that case, mentioning the offset is rather superfluous. – Dennis – 2016-08-10T16:35:44.303

@Dennis Sorry I think that was the result of multiple edits over time. I will edit for clarity, – Post Rock Garf Hunter – 2016-08-10T16:38:52.207

I think this should have spent more time in the sandbox, because I'm sure it wasn't your intention that sequences without B-files should be unsupported. – Peter Taylor – 2016-08-10T18:24:35.133

1@PeterTaylor according to the OeisWiki "If no b-file has been uploaded for a particular sequence, the server generates a b-file containing exactly the terms displayed, for convenience with automated tools." so there should be a B-file for every sequence. Although you may be right about prematurely moving this challenge from the sandbox. – Post Rock Garf Hunter – 2016-08-10T18:29:02.010

1Well, I've learnt something useful today. – Peter Taylor – 2016-08-10T20:07:41.623

What is that last testcase with a negative index? – Scimonster – 2016-08-10T22:09:43.910

@Scimonster The list of Gregory Coefficients A002206 starts at index -1. That would be the first item listed.

– Post Rock Garf Hunter – 2016-08-10T22:27:01.563

relevant tool – Downgoat – 2016-08-10T23:29:31.517

Answers

11

Bash + coreutils + w3m, 51 45 42 bytes

w3m oeis.org/b${1:1}.txt|sed "s/^$2 //p;d"

Thanks to @EamonOlive for golfing off 3 bytes!

Example run

$ bash oeis.sh A172141 7
980

How it works

w3m is a text-based web browser, which displays both HTML and plain text in readable format. Unlike curl, it follows redirects by default (this is required, since oeis.org/bxxxxxx.txt redirects to oeis.org/Axxxxxx/bxxxxxx.txt), doesn't produce any stray output to STDERR, and has a three-byte name.

The command

w3m oeis.org/b${1:1}.txt

the desired URL, where ${1:1} is the first command-line argument without its first character.

The output is piped to the command

sed "s/^$2 //p;d"

which extracts the desired output. s/^$2 //p attempts to replace ^$2  (start of line, followed by the second command-line argument, followed by a space) with the empty string. If the substitution is successful, p prints its result. Afterwards, d unconditionally deletes the pattern to prevent sed from printing the entire input.

Dennis

Posted 2016-08-10T15:28:05.463

Reputation: 196 637

You can save a few bytes by using oeis.org/b${1:1}.txt instead of oeis.org/$1/b${1:1}.txt – Post Rock Garf Hunter – 2016-08-10T16:35:57.913

Heh, I would normally have used sed -n ..., but that would be one more character. – Vatine – 2016-08-11T11:19:52.923

1@Vatine With -n, the double quotes could be replaced with an escaped space, for the same byte count. – Dennis – 2016-08-11T17:27:32.633

3

Perl, 59 bytes

($_,$v)=@ARGV;/./;say`curl oeis.org/$_/b$'.txt`=~/$v (.*)/m

Needs -M5.010 or -E to run. For instance :

$ cat oeis.pl
($_,$v)=@ARGV;/./;say`curl oeis.org/$_/b$'.txt`=~/$v (.*)/m
$ perl -M5.010 oeis.pl A178932 5 2>&-
27

Saved 8 bytes thanks to @Dennis answer, by removing http://, as he did.

Dada

Posted 2016-08-10T15:28:05.463

Reputation: 8 279

3

Mathematica + OEIS.m, 31

(OEISFunction@ToString@#;#@#2)&

example usage: %[A172141,36]


Mathematica, 85

#2/.Rule@@@Import["http://oeis.org/b"<>#~StringDrop~1<>".txt","Data"]~DeleteCases~{}&

example usage: %["A002206",-1]

dbanet

Posted 2016-08-10T15:28:05.463

Reputation: 131

2

Python 3, 153 146 135 bytes

7 bytes thanks to FryAmTheEggman.

6 bytes thanks to Eamon Olive.

5 bytes thanks to Rod.

from urllib.request import*
def f(a,n):
 for l in urlopen("http://oeis.org/b%s.txt"%a[1:]):
  p,q=l.split()
  if n==p.decode():return q

Call it like this:

print(f("A000796","314"))

Run on a machine where the default is utf-8.

Leaky Nun

Posted 2016-08-10T15:28:05.463

Reputation: 45 011

1In my opinion requiring a string for one argument, and a byte array for another is too lenient an input format, and you should just add the bytes required to encode into bytes yourself. Nothing about this challenge makes it reasonable to require raw bytes as input. – orlp – 2016-08-10T15:49:34.930

Can’t you change A%s to %s and then the first a[1:] to a? – Lynn – 2016-08-10T15:52:29.753

@orlp Alright, done. – Leaky Nun – 2016-08-10T15:55:04.757

@Lynn Yes, because apparently I'm stupid. – Leaky Nun – 2016-08-10T15:55:10.740

1@FryAmTheEggman Yes and no. The default is the environment's locale. – Dennis – 2016-08-10T15:59:42.350

@Dennis Right, my mistake. Adding "run on a machine where the default is utf-8" should make it valid. – FryAmTheEggman – 2016-08-10T16:02:29.553

the "http://oeis.org/%s/b%%s.txt"%a%a[1:] can be shortened to "http://oeis.org/b%s.txt"%a[1:]. – Post Rock Garf Hunter – 2016-08-10T16:09:10.873

You don't need the variable "d", you can iterate over the urlopen itself. – Rod – 2016-08-10T16:11:00.403

2

Python 2, 125 118 113 bytes

7 12 bytes saved thanks to Lynn

import re,urllib2 as u;lambda x,y:re.findall("(?<=%d ).*"%y,u.urlopen("http://oeis.org/b%s.txt"%x[1:]).read())[0]

Well heres my go at my own problem. It is likely suboptimal but I think I did a pretty decent job. It creates an anonymous function that takes a string and integer as arguments and returns a string as the result or throws an error if the index is out of range.

This can be made into a 124 bytes full program.

import re,urllib2 as u;print re.findall("(?<=%d ).*"%input(),u.urlopen("http://oeis.org/b%s.txt"%raw_input()[1:]).read())[0]

This prompts the user for the input. First asking for the index and then the A-number of the sequence.

Post Rock Garf Hunter

Posted 2016-08-10T15:28:05.463

Reputation: 55 382

Some tiny saves: import re,urllib2 as u;lambda x,y:re.search("%d (.*)\n"%y,u.urlopen("http://oeis.org/b%s.txt"%x[1:]).read()).group(1) – Lynn – 2016-08-10T16:39:21.180

And lambda x,y:re.split("%d (.*)"%y,u.urlopen("http://oeis.org/b%s.txt"%x[1:]).read())[1] is shorter still! – Lynn – 2016-08-10T16:45:09.070

2

CJam, 36 bytes

"oeis.org/b"r1>+".txt"+gN%Sf%z~\ra#=

Example run

$ cjam oeis.cjam <<< 'A172141 7'
980

Dennis

Posted 2016-08-10T15:28:05.463

Reputation: 196 637

2

R, 94 89 bytes

t=read.table(paste0("http://oeis.org/b",substring(scan(,""),2),".txt"));t[t$V1==scan(),2]

Using sprintf instead of paste0 results in the same bytecount:

t=read.table(sprintf("http://oeis.org/b%s.txt",substring(scan(,""),2)));t[t$V1==scan(),2]

Five bytes saved thanks to plannapus.

pajonk

Posted 2016-08-10T15:28:05.463

Reputation: 2 480

Too bad you can library(stringr) for free and use str_sub for -2 bytes ^^ – AlexR – 2016-08-11T13:52:27.337

@AlexR I don't think I can import a library for free ;-) – pajonk – 2016-08-12T17:40:01.757

Oops, there was a typo in my comment -- Too bad you can't. It was just a first thought for golfing, because stringr is one of my default packages loaded in the .Rprofile of all my projects. – AlexR – 2016-08-12T17:41:15.613

1You don't need to use url, argument file of read.table can be the URL as a character string. – plannapus – 2016-12-26T10:16:32.383

@plannapus Indeed, that's right. Thanks! – pajonk – 2016-12-26T19:01:27.513

2

PHP 5.6, 93 92 bytes

function f($i,$l){echo explode(' ',file('http://oeis.org/b'.substr($i,1).'.txt')[--$l])[1];}

This one is pretty straight forward. Pull the page with file(), get the line at $line - 1 (0-index), explode on the space and print out the second array element from that.

Samsquanch

Posted 2016-08-10T15:28:05.463

Reputation: 271

2

Nim, 123 115 113 bytes

import httpclient,nre,future
(a,n)=>get getContent("http://oeis.org/b"&a[1..^0]&".txt").find re "(?<="&n&r" )\d+"

This is a lambda expression; to use it, it must be passed as an argument to a testing procedure. A complete program that can be used for testing is given here:

import httpclient,nre,future
proc test(x: (string, string) -> RegexMatch) = echo x("A172141", "7") # Your input here
test((a,n)=>get getContent("http://oeis.org/b"&a[1..^0]&".txt").find re "(?<="&n&r" )\d+")

Expects input as two strings. Example usage:

$ nim c oeis.nim
$ ./oeis
980

We use httpclient's getContent proc to get the OEIS b-file, then use a regex to find the line with the index. find returns an Option[RegexMatch], so we use get to retrieve the value from the Option. echo automatically stringifies, so we leave stringification out.

Copper

Posted 2016-08-10T15:28:05.463

Reputation: 3 684

1

Clojure, 103

#(read-string((re-find(re-pattern(str %2" (\\d+)"))(slurp(str"http://oeis.org/b"(subs % 1)".txt")))1)))

re-find finds a vector of first matche's regex groups, it is used as a function and 1 gets the string at position 1. read-string converts string to int. I'm not 100% sure if this regex always finds the correct row.

NikoNyrh

Posted 2016-08-10T15:28:05.463

Reputation: 2 361

1

R, 87 bytes

f=function(A,n)(R<-read.table(gsub("A(\\d+)","http://oeis.org/b\\1.txt",A)))[R$V1==n,2]

Build the URL string with regexes instead of paste or sprintf.

plannapus

Posted 2016-08-10T15:28:05.463

Reputation: 8 610

0

Node.js + request, 109 bytes

x=>n=>require('request')(`http://oeis.org/b${x.slice(1)}.txt`,(a,b)=>console.log(b.body.match(n+` (.+)`)[1]))

Takes the sequence ID and a number.

Mama Fun Roll

Posted 2016-08-10T15:28:05.463

Reputation: 7 234

0

Julia, 88 bytes

x\y=match(Regex("$y (.*)"),readall(Requests.get("http://oeis.org/b$(x[2:end]).txt")))[1]

Golfed with some help from @Dennis!

Make sure you have Requests.jl installed before running.

Mama Fun Roll

Posted 2016-08-10T15:28:05.463

Reputation: 7 234

0

ListSharp, 266 bytes

STRG a=READ[<here>+"\\a.txt"]
ROWS x=ROWSPLIT a BY [","]
STRG a=GETRANGE x[0] FROM [2] TO [a LENGTH]
NUMB y=<c#int.Parse(x[1])c#>
STRG a=DOWNLOAD["http://oeis.org/b"+a+".txt"]
ROWS x=ROWSPLIT a BY [<newline>]
STRG a=GETLINE x [y]
ROWS x=ROWSPLIT a BY [" "]
SHOW=x[1]

Its sad when a language made for web scraping needs so many lines because nesting statements in ListSharp is taboo

downrep_nation

Posted 2016-08-10T15:28:05.463

Reputation: 1 152