5
\$\begingroup\$

Note: although this is tagged as Python, other languages are permitted

Challenge

What you have to do is write the shortest functions to perform the same actions as the following Python 2 built in functions:

Range

>>> range(1, 10, 1)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> range(1, 10, 2)
[1, 3, 5, 7, 9]
>>> range(10, 5, -1)
[10, 9, 8, 7, 6]

range(start, end, step)

When run, this produces an ascending list of numbers. Generally used in for loops, this can also be used for golfing when lists of numbers are required.

Type

>>> type(12)
'int'
>>> type(12.0)
'float'
>>> type('12')
'str'
>>> type([13, 45])
'list'

type(var)

Returns the data type of a variable. The required types are in the examples.

Round

>>> round(0.5, 0)
1.0
>>> round(0.2, 0)
0.0
>>> round(3.14159, 3)
3.142
>>> round(127.56, -2)
100.0
>>> round(12.5640, 2)
12.56
>>> round(1457, -2)
1500

round(number, ndigits)

Given a floating point integer, it rounds it to ndigits. Floor and ceil functions are not allowed. For ties, round away from zero.

Enumerate

Note: Return a list despite the fact that in Python, enumerate returns an object.

>>> enumerate([1, 2, 3, 4])
[[0, 1], [1, 2], [2, 3], [3, 4]]
>>> enumerate(['spam', 'eggs'])
[[0, 'spam'], [1, 'eggs']]

enumerate(array)

Returns a two dimensional list with the index as part of the embedded list.

Rules

People writing in Python must not use the built-in functions listed above (or magic variables). If there are similar built-in functions in your language, you must not use them.

For invalid arguments return 1:

>>> enumerate(23)
1
>>> round(56, 'hello')
1
>>> range('hi', 4, 1)
1

You may use your own functions (range, type, round and enumerate).

Winning

Your score is the sum of the byte count for each function (the function declaration should not be counted). The lowest score wins.

\$\endgroup\$
11
  • 1
    \$\begingroup\$ How should throw a type error work outside of Python? \$\endgroup\$
    – Dennis
    Oct 10, 2014 at 18:15
  • \$\begingroup\$ @BetaDecay - So CJam's , is allowed ? which works like 10 , = [0 1 2 3 4 5 6 7 8 9] ? \$\endgroup\$
    – Optimizer
    Oct 10, 2014 at 18:36
  • \$\begingroup\$ @Optimizer I'm afraid not \$\endgroup\$
    – Beta Decay
    Oct 10, 2014 at 18:57
  • \$\begingroup\$ Does the range version have to work for fewer arguments? For example, range(5) yields [0,1,2,3,4] and range(2,5) yields [2,3,4]. \$\endgroup\$
    – Wrzlprmft
    Oct 12, 2014 at 20:08
  • 4
    \$\begingroup\$ I'm voting to close this question as off-topic because it a multi-part challenge with no interaction between the parts \$\endgroup\$ Nov 14, 2019 at 4:20

9 Answers 9

5
\$\begingroup\$

MIPS

Range - 40

Probably can be golfed much more with x86 or some clever instruction.

Input:

    .text
    .globl main
main:   # Read inputs
    li      $v0, 5      
    syscall         
    move    $t0, $v0
    
    li      $v0, 5      
    syscall         
    move    $t1, $v0
    
    li      $v0, 5      
    syscall         
    move    $t2, $v0

Actual program (writes to stack):

loop:   bgtz    $t2, pos
        ble     $t0, $t1, exit  # i <= end
        j       l   
pos:    bge     $t0, $t1, exit  # i >= end
l:      addi    $sp, $sp, -4    
        sw      $t0, 0($sp) # Push $t1
        add     $t0, $t0, $t2
        j       loop

Type - 12 (non-serious)

In MIPS all registers can be used with integer instructions, even the floating point ones.

    .text
    .globl main
main:
    li      $v0, 4
    la      $a0, msg
    syscall

    .data
msg:        .asciiz "Integer (probably)"
\$\endgroup\$
4
\$\begingroup\$

Ruby, 183

range=->a,b,s{r=[a];r<<a while(a+=s)<b;r<<a} # 38 bytes

type=->x{%w[int float str list 1][[1,1.0,'',[]].find_index{|y|x.class===y}||4]} # 74 bytes

round=->n,d{a=10**d;b=n*a;z=b%1;b-=z<0.5?z:(-1+z);b/a} # 48 bytes

enumerate=->l{(0...l.size).zip l} # 23 bytes

I've not counted the names of the lambdas and the = that follows them. Only type handles invalid input. It returns the String "1" when an object with a class other than Integer, Float, String or Array is given. The other functions blow up when, for example, a Symbol is passed where a Numeric is expected. I suspect Python behaves similarly.

\$\endgroup\$
4
\$\begingroup\$

JavaScript ES 6 - 175 Bytes

I'm counting everything up to the arrow as part of the declaration.

Range 57:

range=(a,b,c)=>{for(r=[i=0];i<Math.ceil((b-a)/c);r[i]=a+i++*c);return r}

Type 45:

type=a=>a.big?'str':a.map?'list':~~a!=a?'float':'int'

Round 54:

round=(a,b)=>(c=Math.pow(10,b),d=a*c,e=d-~~(d),(e<0.5?d-e:d+1-e)/c)

Enumerate 19:

enumerate=a=>a.map((x,y)=>[y,x])
\$\endgroup\$
4
  • \$\begingroup\$ The string type is just str so you can save 3 bytes and comply with the requirements :) \$\endgroup\$
    – Ingo Bürk
    Oct 12, 2014 at 19:00
  • \$\begingroup\$ @IngoBurk Thanks, man :) \$\endgroup\$ Oct 12, 2014 at 21:32
  • \$\begingroup\$ Some errors: type(1.0) returns int, type([1.3]) returns float. Using ternary instead of || produces shorter code! \$\endgroup\$
    – Florent
    Oct 13, 2014 at 9:09
  • \$\begingroup\$ @Florent Thanks for pointing out, but the 1.0 thing can't be fixed because there's no distinction between integers and floating point numbers in JS :T \$\endgroup\$ Oct 14, 2014 at 11:22
3
\$\begingroup\$

Python 2 – 309 303

t=type=lambda x:["list","string","int","float"][(`x`[0]!="[")*(1+(`x`[0]!="'")*(1+("."in`x`)))]
def T(s,a,i,b=1):
    try:return(1/(t(i)=='int'))*eval(s)
    except:return 1
r=range=lambda a,b,i:T("[a]+r(a+i,b,i)if b*i>a*i else[]",a,i,b)
enumerate=lambda a:T("map(list,zip(r(0,len(a),1),a))",a,1)
def round(a,i):b=T("10.**-i/2*a/abs(a)",a,i);return T("a-(a+b)%(b*2)+b",a,i,b)

It’s so long, because it complies with the requirements (if I am not mistaken), in particular returning 1 for invalid input.

Matsjoyce’ answer provided some inspirations.

\$\endgroup\$
1
  • \$\begingroup\$ This is the shortests valid answer (out of this and the Applescript answer), so I've accepted it \$\endgroup\$
    – Beta Decay
    Nov 9, 2014 at 0:53
3
\$\begingroup\$

Python 3 - 199

Range - 48

def range(s,e,g):
 r=[]
 while[s>e,s<e][g>0]:r+=[s];s+=g
 return r

Enumerate - 32

enumerate=lambda x:[[i,x[i]]for i in range(len(x))]

Or

enumerate=lambda x:zip(range(len(x)),x)

But this doesn't return a list

Round - 29

def round(x,a):
 a=10**-a
 return(x+a/2)//a*a

Type - 90

def type(x):
 x=repr(x)
 if x[0]in"'\"":return str
 if x[0]=="[":return list
 return[int,float]["."in x]
\$\endgroup\$
10
  • \$\begingroup\$ Re. the enumerate, what would the other format be? Keep in mind that other languages can't handle objects in the same way. \$\endgroup\$
    – Beta Decay
    Oct 10, 2014 at 19:10
  • \$\begingroup\$ Just use zip, without the list calls, which results in a zip object of tuples (<zip object at 0x7eff05fee948>, which when iterated over produces (0, 'a') (1, 'b') (2, 'c')) \$\endgroup\$
    – matsjoyce
    Oct 10, 2014 at 20:32
  • \$\begingroup\$ Shouldn't range(0,len(x),1) be the same as range(0,len(x))? \$\endgroup\$ Oct 11, 2014 at 19:36
  • 1
    \$\begingroup\$ @proudhaskeller He's using his own definition of range which requires the inclusion of the step \$\endgroup\$
    – Beta Decay
    Oct 11, 2014 at 22:13
  • \$\begingroup\$ @BetaDecay Can we use the builtin range, as it could just be range(len(x))? \$\endgroup\$
    – matsjoyce
    Oct 12, 2014 at 12:22
2
\$\begingroup\$

Haskell, 86

import Data.Typeable
approx f n=toEnum(fromEnum$10^n*f+0.5)/10^n
getType a=typeOf a
range a b c=[a,a+c..b-c/abs c]
enumerate=zip[0..]

In Haskell there is a type system, so I allowed myself to have a Typeable type-class restriction in getType's type (type is a reserved name in Haskell). to clarify, this is impossible in any other way, as in Haskell you can't cast variables to other types and catch the resulting type exceptions - Haskell simply does not have type errors.

The enumerate functions returns a list of two tuples instead of a list of lists, and I figured that if python tuples weren't immutable they would use them instead.

note that there's already a round function in Haskell so I called the round function approx.

\$\endgroup\$
5
  • \$\begingroup\$ People writing in Python must not use the built-in functions.... If there are similar built-in functions in your language, you must not use them. - You violate this rule with typeOf. \$\endgroup\$
    – Beta Decay
    Oct 11, 2014 at 16:04
  • \$\begingroup\$ @BetaDecay but round is a different function - it rounds to a whole number, and it rounds down on 0.5. it is a different function and thus I can use it. \$\endgroup\$ Oct 11, 2014 at 16:23
  • \$\begingroup\$ @BetaDecay about typeOf, because Haskell has a strict type system, this is the ONLY way it is possible. you can't just get an Object, try to cast it and catch the exceptions. \$\endgroup\$ Oct 11, 2014 at 16:24
  • 2
    \$\begingroup\$ Haskell's round would fall under the rule "Floor and ceil functions are not allowed" or the restriction "If there are similar built-in functions in your language, you must not use them", imo. \$\endgroup\$
    – britishtea
    Oct 11, 2014 at 17:02
  • \$\begingroup\$ @britishtea now doesn't use round \$\endgroup\$ Oct 11, 2014 at 18:09
2
\$\begingroup\$

AppleScript, 382

AppleScript is fun to golf but can't compete with other languages. I count the function bodies, but not the declarations of on handler(arg) and end handler.

--range: 82 bytes
on r(i,j,c)
try
set a to{}
repeat while i/c<j/c
set a to a&i
set i to i+c
end
a
on error
1
end
end r

-- type: 131 bytes
on type(x)
try
if x=x as list
"list"
else if x=x as text
"str"
else if x=x as real and"."is in x as text
"float"
else
"int"
end
on error
1
end
end type

-- round: 70 bytes
on round2(x,p)
try
set m to 10^-p
if x<0then set m to-m
(x+m/2)div m*m
on error
1
end
end round2

-- enumerate: 99 bytes
on enumerate(x)
try
set a to{}
repeat with i in r(1,1+count x,1)
set a to a&{{i-1,x's item i}}
end
a
on error
1
end
end enumerate

-- examples: see results in event log
log r(1, 10, 1)
log r(1, 10, 2)
log r(10, 5, -1)
log type(12)
log type(12.0)
log type("12")
log type({13, 45})
log round2(0.5, 0)
log round2(0.2, 0)
log round2(3.14159, 3)
log round2(127.56, -2)
log round2(12.564, 2)
log round2(1457, -2)
log enumerate({1, 2, 3, 4})
log enumerate({"spam", "eggs"})
log enumerate(23)
log round2(56, "hello")
log r("hi", 4, 1)

range

I renamed range to r because my enumerate function calls r.

I use AppleScript errors to detect invalid arguments. If AppleScript raises an error, then the try structure returns 1. Beware that range([1], "10", 1) raises TypeError in Python, but r({1}, "10", 1) is valid here, because AppleScript's operators accept single-item lists and strings as numbers.

The try body is just this:

set a to {}  -- empty list
repeat while i / c < j / c
    set a to a & i  -- append i to list
    set i to i + c
end

The condition needs to be i < j when c is positive, or i > j when c is negative. I golfed it as i/c<j/c, because the division reverses the comparison when c is negative. As a bonus, c being zero raises a division by zero error, so I correctly reject c being zero as invalid.

Beware that set a to a & i is slow because it copies the whole list a every time. The fast way might look like set r to a reference to a, then set end of r to i, but that is not golf.

type

AppleScript's type operator is class of x (or x's class). My own type function uses operator =, because 1 + "1" is 2 but 1 = "1" is false. The try body is this:

if x = (x as list)
    "list"
else if x = (x as text)
    "str"
else if x = (x as real) and "." is in (x as text)
    "float"
else  -- assume x = (x as integer)
    "int"
end

Some arguments are invalid; try calling type(AppleScript) or type(type). Then x as text or x as real raises an error and I return 1. It helps that x as list always works and x as text works with any number.

Because 12 = 12.0 is true, I need another way to tell floats from ints. I observe that 12 as text is "12" but 12.0 as text is "12.0", so I check for "." in string. I have no check for infinities or NaN because trying to compute those would raise errors.

round

I renamed round to round2 because AppleScript has round in its standard additions. The try body is this:

set m to 10^-p
if x < 0 then set m to -m
((x + m / 2) div m) * m

I observe div truncating toward zero. For rounding, I must calculate x + m / 2 when x is positive, or x - m / 2 when x is negative. For golf, I can negate m. In the div m*m part, the negative sign of m cancels itself.

Python's round typically returns a float, but this round2 often returns an integer. AppleScript's operators like to convert floats to integers, perhaps to help 68k Macs with no FPU. (PowerPC Macs emulated a 68LC040 with no FPU.)

enumerate

My enumerate also works with strings. The try body is this:

set a to {}
repeat with i in r(1, 1 + (count x), 1)
    set a to a & {{i - 1, x's item i}}
end
a

I must not use AppleScript's range loop (repeat with i from 1 to count x), but I may call my own range function. I tried to golf away the final a, but I need it when enumerating the empty list or string.

Beware that i is a reference to a number, not the number itself. If I looped in r(0,count x,1) and collected {{i,x's item(i+1)}}, the result might look like {{item 1 of {0, 1}, "spam"}, {item 2 of {0, 1}, "eggs"}}. The operations i-1 and x's item i coerce i to a number.

\$\endgroup\$
2
\$\begingroup\$

APL (43+19+18+38=118)

type←{''≡0↑⍵:'str'⋄⍬≢⍴⍵:'list'⋄⍵=⌈⍵:'int'⋄'float'}  ⍝ 43
round←{0::1⋄∆÷⍨⍎0⍕⍵×∆←10*⍺}                          ⍝ 19
enumerate←{0::1⋄(¯1+⍳⍴⍵),¨⊂¨⍵}                       ⍝ 18
range←{0::1⋄0<∆←-⍺⍺:⌽∆+⍵(∆∇∇)⍺⋄⍺<⍵:⍺,⍵∇⍨⍺-∆⋄⍬}    ⍝ 38

I made the argument order consistent with general APL style.

Ungolfed, with explanation.

Test:

      ⍝ range: <start> <step> range <end>
      1 (1 range) 10
1 2 3 4 5 6 7 8 9
      1 (2 range) 10
1 3 5 7 9
      10 (¯1 range) 5
10 9 8 7 6
      ⍝ type: type <obj>. 
      ⍝ 1.0 is considered int, because APL itself does not make the distinction
      type 12
int
      type 12.1
float
      type '12'
str
      type (13 45)
list
      ⍝ APL's native type function: 
      ⎕DR¨ 12 12.0 12.1
83 83 645
      ⍝ round: <digits> round <value>
      0 round 0.5
1
      0 round 0.2
0
      3 round 3.14159
3.142
      ¯1 round 127.56
130
      ¯2 round 127.56
100
      2 round 12.5640
12.56
      ¯2 round 1457
1500
      ⍝ enumerate: enumerate <list>
      enumerate 1 2 3 4
┌───┬───┬───┬───┐
│0 1│1 2│2 3│3 4│
└───┴───┴───┴───┘
      enumerate 'spam' 'eggs'
┌────────┬────────┐
│┌─┬────┐│┌─┬────┐│
││0│spam│││1│eggs││
│└─┴────┘│└─┴────┘│
└────────┴────────┘
\$\endgroup\$
2
  • \$\begingroup\$ Does APL work right to left? I've seen several cases where strings were written backwards... \$\endgroup\$
    – Beta Decay
    Oct 13, 2014 at 15:57
  • 2
    \$\begingroup\$ @BetaDecay: there is no operator precedence, so everything is executed right-to-left, i.e. a F b G c means F(a,G(b,c)). So that also means G must run before F does. If you want the equivalent of G(F(a,b),c), you have to use braces, i.e. (a F b) G c. So that means that if you're writing a function like round, you want to make the precision the left argument and the input the right argument, because you're far more likely to write something like "round all these numbers to three decimal places" than "round this number to zero, one, two, and three decimal places". \$\endgroup\$
    – marinus
    Oct 13, 2014 at 17:41
0
\$\begingroup\$

Axiom, 438 445 bytes

The macro used 18 bytes

I==>"int";T==>type

Two macros named I=="int" and T=="type"

the type function 124 bytes

T a==(y:=(tex domainOf a).1;suffix?("Integer()",y)=>I;y="Float()"=>"float";y="String()"=>"str";prefix?("List ",y)=>"list";y)

Function type()[or T] that retrun "int" "float" or "list" it depend of the type of its argument. It can not fail, it would return the right string for the type int, float, list of ???, string, or othewise would return one unknow string different, in Tex language that says its type in Axiom. Example:

(26) -> q:=set [x**2-1, y**2-1, z**2-1];type(q)
   (26)  "Set \left( {{Polynomial \left( {{Integer()}} \right)}} \right)"
                                                             Type: String

the round function 152 bytes

Round(a,c)==(v:=T a;(v~="float"and v~=I)or T c~=I=>%i;a<0=>-Round(-a,c);z:=a*10.^c;x:=truncate(z);w:=0.5+x-z;0<=w and w>10^-digits()=>x/10^c;(x+1)/10^c)

It would return the Round() of the number (it is in count the error of float so we impose bheaviour of it is of the kind Round(0.4999999999999999999, 0) is 0.0 but Round(0.499999999999999999999, 0) is 1.0 and so Round(0.49999999999999999999999999999999, 0) is 1 too). if Round(a,c) find one error it return the complex number %i [the complex costant i]. I don't know how write it without one call one function equivalent to floor (I'm sorry)

the range function 95 bytes

Range(a,b,c)==(T a~=I or T b~=I or T c~=I=>[];[a+c*i for i in 0..(Round((b-a)/c*1.,0)::INT-1)])

It would return the result range as a list of number; if find one error it would return the void list []. It use the above type() and Round(,) function too.

The enumerate function 56 bytes

enumerate a==(T a~="list"=>[];[[i-1,a.i]for i in 1..#a])

It would enumerate the element of the list as in the question; in case of error return [] void list.

Result in the session

(5) -> [[i,j,Round(i,j)] for i in [0.5,0.2,3.14159,127.56,12.5640,1457] for j in [0,0,3,-2,2,-2]]
   (5)
   [[0.5,0.0,1.0], [0.2,0.0,0.0], [3.14159,3.0,3.142], [127.56,- 2.0,100.0],
    [12.564,2.0,12.56], [1457.0,- 2.0,1500.0]]
                                            Type: List List Complex Float
(6) -> Range(1,10,1)
   (6)  [1,2,3,4,5,6,7,8,9]
                                                       Type: List Integer
(7) -> Range(1,10,2)
   (7)  [1,3,5,7,9]
                                                       Type: List Integer
(8) -> Range(10,5,-1)
   (8)  [10,9,8,7,6]
                                                       Type: List Integer
(9) -> type(12)
   (9)  "int"
                                                             Type: String
(10) -> type(12.0)
   (10)  "float"
                                                             Type: String
(11) -> type([13,45])
   (11)  "list"
                                                             Type: String
(12) -> enumerate([1,2,3,4])
   (12)  [[0,1],[1,2],[2,3],[3,4]]
                                                  Type: List List Integer
(13) -> enumerate(["spam","eggs"])
   (13)  [[0,"spam"],[1,"eggs"]]
                                                      Type: List List Any
(14) -> enumerate(23)     -- error for enumerate
   (14)  []
                                                          Type: List None
(15) -> Round(56,"hello") -- error for Round
   (15)  %i
                                                    Type: Complex Integer
(16) -> Range("hi",4,1)   -- error for range
   (16)  []
                                                          Type: List None

In total and in partial too it is a very good question: Thank you very much.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.