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\$
  • 2
    \$\begingroup\$ Convienient number list \$\endgroup\$ – Lyxal Oct 3 at 7:23
  • 1
    \$\begingroup\$ Relatedly, do we have to include zero? \$\endgroup\$ – Shaggy Oct 3 at 7:34
  • \$\begingroup\$ the input is a whole number, so zero is required. \$\endgroup\$ – Razetime Oct 3 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 Oct 3 at 12:33
  • \$\begingroup\$ Added the exception. @elementiro \$\endgroup\$ – Razetime Oct 3 at 12:35

16 Answers 16

9
\$\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.
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I wonder what sequence this is... \$\endgroup\$ – Razetime Oct 4 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.

| improve this answer | |
\$\endgroup\$
  • 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\$ – Dominic van Essen Oct 6 at 8:58
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
| improve this answer | |
\$\endgroup\$
6
\$\begingroup\$

J, 40 39 bytes

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

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ [{.>@{{~<:@[(0,1<.@+|@[+/\@$%~)_2+#@>@{ is an alternative for the same byte count - inspired by Lynn's Haskell answer. \$\endgroup\$ – Galen Ivanov Oct 6 at 9:24
6
+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
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks! I couldn't find any easier answers, because you seem to have already done them all! \$\endgroup\$ – Dominic van Essen Oct 5 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 Oct 5 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 Oct 5 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 Oct 5 at 17:38
  • 2
    \$\begingroup\$ Some of the superscripts can still be removed. 21 bytes \$\endgroup\$ – Zgarb Oct 6 at 7:06
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

| improve this answer | |
\$\endgroup\$
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!

| improve this answer | |
\$\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!

| improve this answer | |
\$\endgroup\$
  • 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 Oct 3 at 18:49
  • \$\begingroup\$ @ovs Thanks, it saves 4 bytes! \$\endgroup\$ – Galen Ivanov Oct 3 at 19:41
  • \$\begingroup\$ From Review: {x#,/(1,(+/'(-2+#y;0N)#2_x#1),1)#'y}. Credits to @coltim \$\endgroup\$ – caird coinheringaahing Oct 4 at 0:35
  • \$\begingroup\$ @cairdcoinheringaahing Thank you for your comment! \$\endgroup\$ – Galen Ivanov Oct 4 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\$ – Galen Ivanov Oct 4 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].

| improve this answer | |
\$\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.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ -2 bytes(Dict is too long for a comment): Try it online! \$\endgroup\$ – Razetime Oct 4 at 7:01
  • \$\begingroup\$ You can remove the assignment for -1 byte if you swap the order of the parameters \$\endgroup\$ – Jo King Oct 4 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.)

| improve this answer | |
\$\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!

| improve this answer | |
\$\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
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I think you need to update your TIO link with m.indices instead of 1.to(i-2) \$\endgroup\$ – user Oct 9 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 Oct 13 at 19:17
  • \$\begingroup\$ Ah, you're right, didn't read the rules too carefully \$\endgroup\$ – user Oct 13 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.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ What do you mean by a lazy infinite result? \$\endgroup\$ – Razetime Oct 6 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\$ – Kevin Cruijssen Oct 6 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!

| improve this answer | |
\$\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
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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