19
\$\begingroup\$

Intro

enter image description here

Given a whole number \$< 100,\$ extend/shorten the english representation of the number to have as many characters as it's value.

Sandbox

Rules

Take the number \$n\$, and get it in words from this dictionary. You may take this dictionary in any way you prefer. (a list, read from link, command line arg, STDIN, variable, so on.)

Here's the file as a JSON Array. (Courtesy of Lyxal)

Then, do the following with the string:

  • If the string's length is lower than the number, repeat some of its characters in place until the length matches the number.
  • The first and last characters should not be repeated, and the numbers of repetitions of the other characters should differ by at most one (so you can repeat some of them 5 times and others 6 times, for example; it doesn't matter which ones exactly).
  • If the string's length is greater than the number, remove any of its characters except the first and last to make the length match the number. 1 and 0 are exceptions, since they are too small.
  • The order of the letters in the string must be maintained.
  • Example:
50 → f[ift]y → 3 letters must be duplicated 16 times
61 → s[ixtyon]e → 5 letters must be duplicated 10 times, 1 character must be duplicated 9 times

Step by step run-through

Taking 11 as an example,

(formatted as word → length)

eleven → 6
 ^
elleven → 7
   ^
elleeven → 8
     ^
elleevven → 9
       ^
elleevveen → 10
  ^
ellleevveen → 11 (end)

Examples

2 → to
3 → the or tre or tee
4 → four
5 → fiive or fivve
7 → seevven or sevveen or seeveen 
10 → teeeeeeeen

Special cases:
0 → (Any null value/no output)
1 → o

Winning Criteria

This is . Shortest code in each language wins.

LoTM Bounty Claimed by Dominic Van Essen!

The first Husk answer to this question will get a +50 rep bounty from me on top of Zgarb's bounty, if it satisfies the criteria put up here in the Additional Efforts part.

\$\endgroup\$
5
  • 2
    \$\begingroup\$ Convienient number list \$\endgroup\$
    – lyxal
    Commented Oct 3, 2020 at 7:23
  • 1
    \$\begingroup\$ Relatedly, do we have to include zero? \$\endgroup\$
    – Shaggy
    Commented Oct 3, 2020 at 7:34
  • \$\begingroup\$ the input is a whole number, so zero is required. \$\endgroup\$
    – Razetime
    Commented Oct 3, 2020 at 7:40
  • 3
    \$\begingroup\$ remove any of its characters except the first and last to make the length match the number. - this can't be done for 0 and 1, since with them you have to remove first/last letter for length to match the number. You should exclude 1 and 0 from that requirement. \$\endgroup\$
    – elementiro
    Commented Oct 3, 2020 at 12:33
  • \$\begingroup\$ Added the exception. @elementiro \$\endgroup\$
    – Razetime
    Commented Oct 3, 2020 at 12:35

16 Answers 16

10
\$\begingroup\$

R, (110 105 96) 96 95 bytes

Hopefully answering the correct question now...

function(n,a)cat(substring(b<-a[n+1],r<-sort(c(1,l<-nchar(b),rep(3:l-1,n))[1:n]*!!n),r),sep='')

Try it online!

Doh! Read the question, stupid!

Ok, first (several) attempts were not answering the correct question, because I didn't read the challenge properly and didn't notice that the first+last characters shouldn't be repeated. Coincidentally, though, the near-complete-rewrite came out at the same number of bytes!

How? Ungolfed code:

size_up=
function(n,a){              # n is number, a is array of text strings
  b=a[n+1]                  # get the text string for this number
  l=nchar(b)                # get the number of characters
  r=sort(                   # r = sort the indices of characters to output:
      c(1,l,                # we need index 1 and the last index (l)...
        rep(2:(l-1),n))     # then plenty of repeats of 2..(l-1) ...
      [1:n])                # and, from this, we'll use the first n.
  if(n)                     # only output anything if n>0 ...
    cat(substring(b,r,r),sep='')
                            # ...in which case concatenate the indexed
}                           # characters of the text string b.
\$\endgroup\$
1
  • \$\begingroup\$ I wonder what sequence this is... \$\endgroup\$
    – Razetime
    Commented Oct 4, 2020 at 5:06
7
\$\begingroup\$

Haskell, 59 bytes

d!n|h:t<-d!!n=take n$h:[t!!div(i*length t-i)(n-1)|i<-[1..]]

Try it online!

Usage: ["zero","one",...]!n.

For example, for input 11, it will output an 'e' followed by "leven" indexed at: $$ \left\lfloor\frac{4}{10}\right\rfloor, \left\lfloor\frac{8}{10}\right\rfloor, \dots, \left\lfloor\frac{40}{10}\right\rfloor $$ which is "lleevvveen". (Intuitively, the formula stretches the indices [0..4] of "leven" to [0..10].)

take n$ is used to support the 0 case (otherwise the output is "z"), but it also lets us write [1..] instead of [1..n-1], so the net cost is only 4 bytes rather than 7.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ This is a very nice approach, and seems so obvious now that I've seen it... (so why didn't I think of it???) \$\endgroup\$ Commented Oct 6, 2020 at 8:58
7
+100
\$\begingroup\$

Husk, 28 27 25 22 21 bytes

Edit: -2 bytes thanks to Zgarb, -3 more bytes thanks to Jo King, and then -1 more byte thanks again to Zgarb (those last 4 bytes took a while to work-through and understand; I've added an explanation but it isn't easy for Husk newbies like me...)

SṀ!(O↑¹:1S:ȯ*¹…2←L)!→

Try it online!

My first Husk answer, inspired by the 'language of the month'.
Port of the approach in my R answer.
I'm pretty happy just to figure-out how to write a working program (hooray!), so it's almost-certainly not as golfy as it could be...

How? (commented after Zgarb & Jo King's golfs: it's quite complicated now...):

First of all, we'll put-in all the implicit arguments (as superscripts and ²):

SṀ!(O↑²:1S:ȯ*²…2←L)!→²⁰

Now the commented code:

S                               # S is a 'hook' combinator to recycle argument x: Sfgx == fx(gx)
 Ṁ!                             # f is M! = map the list-index function across a list of indexes, with the list to index given by argument x
   (O↑²:1S:ȯ*²…2←L)             # g is (O↑²:1S:ȯ*²…2←L) = function to generate the list of indexes from argument x (see below)
                   !→²⁰         # x is !→²⁰ = the text name of the number (for instance, "twenty"; see below)

                                # Explanation of g:
         S                      # S 'hook' combinator again, so Sfgy here == fy(gy)
          :                     # f is : = prefix with y
           ȯ                    # g is given by ȯ*²…2←
                                # ȯ is 3-function combinator: ȯfgh == single function fgh
                ←               #   subtract 1
              …2                #   and construct a series from 2..this value,  
            *²                  #   and repeat this series n times, with n given by argument 2 (first given program argument);
                                #   so ȯ*²…2← is the function that repeats 2..x, n times, for argument y
                 L              # y is the length of the argument x
                                # So: up to here, we have :Lx *²…2←Lx
       :1                       # Now prefix with 1...
     ↑²                         # then select the first n elements, with n given by argument 2 (first given program argument)...
    O                           # and sort the result.  This is the list of indexes from x.
    
                                # Explanation of x:
                   !  ⁰         # element of argument 1 (second given), indexed by...
                    →²          # argument 2 (first given) +1
\$\endgroup\$
11
  • 1
    \$\begingroup\$ Thanks! I couldn't find any easier answers, because you seem to have already done them all! \$\endgroup\$ Commented Oct 5, 2020 at 9:04
  • 2
    \$\begingroup\$ Nice first Husk answer! Each +1 can be and -1 can be . That many superscripts looks funky... Reusing arguments isn't as elegant in Husk as Jelly. \$\endgroup\$
    – Zgarb
    Commented Oct 5, 2020 at 16:33
  • 1
    \$\begingroup\$ It's not that obvious in shorter challenges, but longer programs do have a lot of these. Generally, combinators help a lot with single expressions, but otherwise, not many other ways to get around them. \$\endgroup\$
    – Razetime
    Commented Oct 5, 2020 at 17:23
  • 1
    \$\begingroup\$ There are combinators that "locally copy" values or functions so they can be used at two places. Sometimes they don't fit the program nicely, though, and you have to put up with some repetition since it's shorter. \$\endgroup\$
    – Zgarb
    Commented Oct 5, 2020 at 17:38
  • 2
    \$\begingroup\$ Some of the superscripts can still be removed. 21 bytes \$\endgroup\$
    – Zgarb
    Commented Oct 6, 2020 at 7:06
6
\$\begingroup\$

Jelly, 20 bytes

ị©L⁸,_2œs/Ẉ⁸>Ø.¤j®x"

A dyadic Link accepting the number on the left and the list of number-names on the right (in Jelly index order), which yields a list of characters.

Try it online! Or see all 100.

How?

ị©L⁸,_2œs/Ẉ⁸>Ø.¤j®x" - Link: N, Words
ị                    - (N) index into (Words) -> the word
 ©                   - copy for later
  L                  - length
   ⁸                 - chain's left argument -> N
    ,                - pair -> [N, length(Word)]
     _2              - subtract two -> [N-2, length(Word)-2]
         /           - reduce using:
       œs            -   split (implicit range [1..N-2]) into (length(Word)-2)
                         approximately equal parts
          Ẉ          - length of each -> sizes (call this [s1, s2, ...])
               ¤     - nilad followed by link(s) as a nilad:
           ⁸         -   chain's left argument -> N
             Ø.      -   bits -> [0,1]
            >        -   greater than? -> [N>0, N>1]
                j    - join -> [N>0, s1, s2, ..., N>1]
                 ®   - recall from earlier -> the word
                   " - zip with:
                  x  -   repeat
\$\endgroup\$
6
\$\begingroup\$

J, 40 39 bytes

[{.[(]#~1:0 _1}2+/@}.($[:}:@}.@=#\))>@{

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ [{.>@{{~<:@[(0,1<.@+|@[+/\@$%~)_2+#@>@{ is an alternative for the same byte count - inspired by Lynn's Haskell answer. \$\endgroup\$ Commented Oct 6, 2020 at 9:24
5
\$\begingroup\$

Python 3, 98 bytes

def f(n,a):x,*s,y=a[n];l=len(s);d=n-2;a[0]=(x+"".join(s[i]*(d//l+(i<d%l))for i in range(l))+y)[:n]

Try it online!

-8 bytes thanks to ovs
-2 bytes thanks to pxeger

(-9 bytes between the two because one of the saved bytes overlaps between the two optimizations)

-9 more bytes thanks to ovs

\$\endgroup\$
3
5
\$\begingroup\$

JavaScript (ES6),  78  73 bytes

Expects (n)(dictionary). Returns an empty string for zero.

n=>d=>(s=d[n--],g=k=>k<n?s[~k?k/~-n*(s.length-2)+1|0||2:0]+g(k+1):'')(-1)

Try it online!

\$\endgroup\$
5
\$\begingroup\$

K (oK), 50 46 40 bytes

-4 bytes thanks to ovs

-6 bytes thanks to coltim

{x#,/(1,(+/'(-2+#y@x;0N)#2_x#1),1)#'y@x}

Try it online!

\$\endgroup\$
5
  • 2
    \$\begingroup\$ I don't know K, but can you replace (x>0) and x>1 with 1 and take the required number of characters at the end? \$\endgroup\$
    – ovs
    Commented Oct 3, 2020 at 18:49
  • \$\begingroup\$ @ovs Thanks, it saves 4 bytes! \$\endgroup\$ Commented Oct 3, 2020 at 19:41
  • \$\begingroup\$ From Review: {x#,/(1,(+/'(-2+#y;0N)#2_x#1),1)#'y}. Credits to @coltim \$\endgroup\$ Commented Oct 4, 2020 at 0:35
  • \$\begingroup\$ @cairdcoinheringaahing Thank you for your comment! \$\endgroup\$ Commented Oct 4, 2020 at 7:20
  • \$\begingroup\$ @coltim Thank you - obviously 2_x#1 is the right way to do it. I prefer to pass the entire "dictionary" as an argument though. \$\endgroup\$ Commented Oct 4, 2020 at 7:23
4
\$\begingroup\$

Rust, 203 bytes

|i,a|if i<2{a[i].truncate(i)}else
if let[f,m@..,l]=&*a[i].clone(){let mut v:Vec<_>=(0..m.len()).cycle().take(i-2).collect();v.sort();a[i]=v.iter().map(|&j|m[j]).collect();a[i].insert(0,*f);a[i].push(*l)}

Try it online

A closure of type fn(usize,&mut [Vec<char>]). The result is written in a[i].

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

APL (Dyalog Unicode), 39 37 36 bytes

-2 bytes thanks to Razetime!
-1 byte thanks to Jo King!

Assumes ⎕IO←0.

⊃∘⌷{⍵↑⍺/⍨1,⍨1,(⍵-2)(⌊÷+|⍨>∘⍳⊢)≢2↓⍺}⊣

Try it online!

Explanation

This function takes the dictionary as the right argument and the integer as the left argument.

⊃∘⌷ is a function that gets the word at the left index in the right dictionary.
is the left identity function.
The inner function { ... } is then called with the word as a left argument and the integer as a right argument .

≢2↓⍺ is the length of the word without the first two characters (a).
⍵-2 is just the integer input minus 2 (b).

With these two arguments the function ⌊÷+|⍨>∘⍳⊢ is called:
⍳⊢ creates an index vector 0 1 ... a-1.
|⍨ calculates b mod a.
> compares this to the index vector, which results in a boolean vector with b mod a 1's and a - b mod a 0's.
⌊÷ is the floor of b÷a.
+ adds this to the boolean vector.

1, prepends a 1, 1,⍨ appends a 1.
⍺/v selects as many items from the word x, as indicated in v. Example: 1 3 2 2 2 1/'eleven'≡'ellleevveen'. This is commuted () here to avoid brackets.
⍵↑ then takes the required number of characters. This is required for 0 and 1.

\$\endgroup\$
2
  • \$\begingroup\$ -2 bytes(Dict is too long for a comment): Try it online! \$\endgroup\$
    – Razetime
    Commented Oct 4, 2020 at 7:01
  • \$\begingroup\$ You can remove the assignment for -1 byte if you swap the order of the parameters \$\endgroup\$
    – Jo King
    Commented Oct 4, 2020 at 22:58
3
\$\begingroup\$

Charcoal, 29 bytes

NθF⊕θSηFθ§η∧ι⊖÷×⊕⁻ιθ⁻²Lη∨⁻²θ¹

Try it online! Link is to verbose version of code. Takes input as the number and then the dictionary. Removing the F⊕θSη results in a program that resizes the second line to the length given on the first line. Annoyingly, 2 was the hardest number to process, since both the first and last character are edge cases. Explanation:

Nθ

Input n.

F⊕θSη

Read in the dictionary up until and including the entry for n.

Fθ

Loop over n characters. (⭆θ also works.)

§η

Output the character of the dictionary word given by the computed index.

∧ι

For the first character of the output the computed index is always 0.

⊖÷×⊕⁻ιθ⁻²Lη∨⁻²θ¹

Otherwise scale the distance to the end of the string from 0..n-2 to 0..l-2 (where l is the length of the dictionary word), rounded up. Note that this results in 0/0 for n=2, so the denominator is coerced to 1 in this case. Example for n=5, five:

i=0 o=0
i=1 o=3-ceil((4-1)*(4-2)/(5-2))=3-ceil(3*2/3)=3-2=1
i=2 o=3-ceil((4-2)*(4-2)/(5-2))=3-ceil(2*2/3)=3-2=1
i=3 o=3-ceil((4-3)*(4-2)/(5-2))=3-ceil(1*2/3)=3-1=2
i=4 o=3-ceil((4-4)*(4-2)/(5-2))=3-ceil(0*2/3)=3-0=3

Therefore the output indices are 0, 1, 1, 2, 3 resulting in fiive. (In actual fact the calculations are done using negative indices, so the actual indices are 0, -3, -3, -2, -1, which means that they are actually rounded down, rather then up.)

\$\endgroup\$
3
\$\begingroup\$

Perl 5, 77 bytes

sub{@w=@{$d[$n=pop]};$h=$n<4?2:(@w-2)/($n-2);join'',@w[map.99+$h*$_,0..$n-1]}

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Scala, 93 bytes

i=>a=>{val f+:m:+l=a(i);(f+:Seq.fill(i)(m.indices).flatten.take(i-2).sorted.map(m):+l)take i}

Try it online!

Defines a function of type Int=>Seq[Seq[Char]]=>Seq[Char].

Explanation:

i => a => {                  // define a curried lambda function with two arguments
  val f+:m:+l = a(i)         // destructure the string to extract the first and last letter
  (                          // return...
    f +:                     // the first letter prepended to
      Seq.fill(i)(m.indices) // the numbers from 0 to i-2, all repeated i times
                             // for "seven", this is 7 instances of [0,1,2]
      .flatten               // flatten this list
      .take(i-2)             // take the first i-2  numbers from the list
      .sorted                // sort them
      .map(m)                // and use them as indices for the middle part of the string
    :+l                      // append l
  )
  take i                     // to handle 0 and 1, take i letters from the result
}
\$\endgroup\$
3
  • \$\begingroup\$ I think you need to update your TIO link with m.indices instead of 1.to(i-2) \$\endgroup\$
    – user
    Commented Oct 9, 2020 at 16:55
  • 1
    \$\begingroup\$ @user That produces List(s, s, s, e, v, e, n) which isn't valid (can't repeat the first or last letter). \$\endgroup\$
    – corvus_192
    Commented Oct 13, 2020 at 19:17
  • \$\begingroup\$ Ah, you're right, didn't read the rules too carefully \$\endgroup\$
    – user
    Commented Oct 13, 2020 at 19:21
2
\$\begingroup\$

05AB1E, 20 bytes

èā¨¨₂и¾šηε{®ª}0šδè¹ù

Takes the list of words as additional second input.
Outputs as a list of characters.

Try it online or verify all \$[0,99]\$ test cases.

Explanation:

è                  # Index the (implicit) input-integer into the (implicit) string-list
 ā                 # Push a list in the range [1,string-length] (without popping)
  ¨¨               # Remove the last two values to make the range [1,length-2]
    ₂и             # Repeat this list 26 times: [1,2,3] → [1,2,3,1,2,3,1,2,3,...]
      ¾š           # Prepend a 0 to this list
        η          # Take all prefixes
         ε         # Map each prefix-list to:
          {        #  Sort the list
           ®ª      #  And append a -1
         }0š       # After the map: prepend a 0 to the list of lists
             δ     # Map over each list:
              è    #  Index it in the string that's still on the stack
                   #  (modulair 0-based, so the -1 indexes into the last character)
               ¹ù  # Keep the list of characters of a length equal to the first input
                   # (after which the result is output implicitly as result)

If outputting a lazy infinite result is allowed, the ₂и could be Þ instead for -1 byte: try it online.

\$\endgroup\$
2
  • \$\begingroup\$ What do you mean by a lazy infinite result? \$\endgroup\$
    – Razetime
    Commented Oct 6, 2020 at 2:16
  • \$\begingroup\$ @Razetime Þ results in an infinite list, so the TIO at the bottom does eventually output the result of the ù filter, but only after timing out after 60 seconds. So it's probably invalid, since outside of TIO it would never terminate and output I think.. \$\endgroup\$ Commented Oct 6, 2020 at 7:23
1
\$\begingroup\$

Factor, 201 bytes

: s ( n d -- s ) dupd 2dup nth length 2 - pick 1 - 1 max dup [ / ] dip swap
<repetition> dup first [ + ] accumulate [ 1 + >integer ] map nip [ nth ] dip
dupd swap nths [ 1 head ] dip append swap head ;

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Japt, 25 bytes

gV
_uUÊ-2 Ä}hV[0UÊÉ] Í®gU

Try it

Input :
 U = dictionary
 V = number

gV          - get element from dictionary

hV[0UÊÉ]    - build a list of V indexes,
              starting with [0 , last idx] 
              and calling the following function on last element to generate next items.
_uUÊ-2 Ä}   - returns number modulo( literal length -2) + 1

Example : 11 - eleven
[0,5] -> 5%4+1
[0,5,2] -> 2%4+1
[0,5,2,3]
[0,5,2,3,4,1,..]
     
ͮgU         - sort and maps to literal

-P flag to join result
\$\endgroup\$

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