# Output all numbers in certain range containing certain digits

1. Take an input of digits through console, prompt, or a file (in the decimal number system). These digits should be separated by spaces.
2. Take an input of the "maximum" through console, prompt, or a file
3. If you use a file, the program must output "[Data taken from file]"
4. Print all natural numbers (including 0) below the maximum containing at least one of the digits specified by the user (they may contain other digits), separated by a single space. Leading 0s do not count!
5. If there is a sequence of 10 or more consecutive numbers, it should output the first and last, separated by a -->

### Rules

• Standard loopholes are (obviously) not allowed
• Programs must complete the tasks above
• The answer with the fewest characters wins

### Examples

>>> 1 3
>>> 100
1 3 10 --> 19 21 23 30 --> 39 41 43 51 53 61 63 71 73 81 83 91 93


>>> 1 2 4 5 6 7
>>> 29
1 2 4 5 6 7 10 --> 28


>>> 0 1 2 3 4 5 6 7 8 9
>>> 9999999
0 --> 9999998


[Data taken from file]
1 3 5 7 9

• Please be specific about the format for digits input: space separated (as in examples), comma separated, a single string (136) or whatever. – edc65 Sep 21 '14 at 15:09
• Does the arrow have to be -> or would a Unicode arrow like → also be fine? – Martin Ender Sep 21 '14 at 20:21
• @MartinBüttner It has to be -->. – monopole Sep 21 '14 at 20:30

## GolfScript 74 71 (DEMO)

' ':§/)~\n*:x;,{x&},99:c;{.c)=!{§\}*:c}%[§]/{.,9>{('-->'@)\;}{~}if}%§*


### Description:

The code expects the parameters passed via the console, like so:

echo "1 3 100" | ruby golfscript.rb numbers.gs


Here's the annotated code:

' ':§/                  # Split input by space and save the
# space character in variable §

)~                      # Take the last input and convert to int
# This is the "maximum" parameter.

\n*:x;                  # Take the list of digits and join them with
# newlines, resulting in a string.
# Save the result in variable x and take it
# off the stack

,                       # Take the "maximum" parameter and make an
# array [0, max)

{x&},                  # Filter the array, leaving only numbers that
# contain the right digits (that have at least
# one char in common with string x)

99:c;                   # Save the value 99 in a new variable, c.

{                       # For each element (n) in the array:
.                     #   - duplicate n on the stack
c)=!{§\}*             #   - if it does not equal c+1 add a space before it
:c                    #   - assign the value of n to c
}%

[§]/                    # Split the resulting array by spaces

{                       # For each element a in the array of arrays:
.                     #   - duplicate a on the stack
,9>                   #   - check if length > 9
{('-->'@)\;}          #   - if a's length is >9, then push "(min)", "-->" and "(max)"
#     on the stack
{~}if                 #   - otherwise, just place the elements of the current array
#     on the stack
}%
§*                      # make a string representing the elements of the resulting array,
# separated by spaces


## Ruby, 186181 177 bytes

a=gets.split;puts ([0]+(0...gets.to_i).select{|x|(x.to_s.split('')&a).any?}).each_cons(2).slice_before{|m,n|m+1<n}.map{|a|c=a.map &:last;c.count>9?[c[0],'-->',c.last]:c}.join' '


Ungolfed explanation:

# Read numbers from input and split into array
a = gets.split

# Loop from 0 to maximum number, exclusive
puts ([0]+(0...gets.to_i).select { |x|
# Only include numbers that include at least one input digit
(x.to_s.split('')&a).any?
})    # Add dummy element to the beginning of array
.each_cons(2)   # Get each array of 2 consecutive elements
.slice_before { |m, n| #
m + 1 < n # "Slice" the array if m and n are not consecutive
}.map { |a|
c = a.map &:last # Get all the last elements in a
if c.count > 9
# 10 or more consecutive elements. Get the first and last, and
# an arrow in-between
[c[0],'-->',c.last]
else
c
end
}.join ' ' # Add space in-between all elements, and print result


# JavaScript (E6) 153 157 161 163 177

Input and output via prompt

The main loop filters the numbers with a regexp and builds spans of consecutive numbers (as arrays). The O function concatenates the spans converting them to string. If the elements in a span array are 10 or more, instead of taking all elelements it just take the first and last number.

Test in FireFox/FireBug console

P=prompt,m=P(d=P());
O=_=>(
o+=s[9]?s[0]+" -->"+p:s.join(''),s=[]
);
for(s=[o=''],p=n=0;n<m;++n)
(n+'').match("["+d+"]")&&
(
n+~p&&O(),s.push(p=' '+n)
);
O(),P(o)


## Mathematica, 233191171 165 bytes

t=StringSplit;Flatten[Split[Cases[Range@Input[d=t@InputString[]]-1,m_/;ToString@m~t~""⋂d!={}],#2-#<2&]/.{e:{__Integer}/;Length@e>9:>{#&@@e,"-->",Last@e}}]~Row~"  "


I'm taking the input from two prompts which is as close to command line as it gets in Mathematica.

Ungolfed:

t = StringSplit;
Flatten[
Split[
Cases[
Range@Input[d = t@InputString[]] - 1,
m_ /; ToString@m~t~"" \[Intersection] d != {}
],
#2 - # < 2 &
] /. {e : {__Integer} /; Length@e > 9 :> {# & @@ e, "-->", Last@e}}
]~Row~"  "


I'm simply filtering a range with all numbers to the relevant ones and then I'm collapsing consecutive subsequences with a repeated rule replacement.

• Shorter, using String to aid finding runs: t = StringSplit; Row[Flatten[ Split[ (Cases[Range[Input[d = t@InputString[]] - 1], m_ /; ToString@m~t~"" \[Intersection] d != {}]), #2 - # == 1 &] /. {e : {a__Integer} /; Length[{a}] > 9 :> {e[[1]] -> e[[-1]]}}], " "] – DavidC Sep 21 '14 at 19:53
• @DavidCarraher Nice! Thanks a lot. I don't think the -> shortcut is fair game though. I'll ask the OP. – Martin Ender Sep 21 '14 at 20:13
• Shouldn't it be Range[0, Input[d = t@InputString[]] - 1] instead of Range[Input[d = t@InputString[]] - 1]? – DavidC Sep 21 '14 at 23:04
• @DavidCarraher Oh, I didn't see that 0 was included. But in that case decrementing the default range by 1 is shorter. – Martin Ender Sep 21 '14 at 23:05
• Yes, it's shorter, but it only tests through max-1, not max. – DavidC Sep 21 '14 at 23:40

# Ruby, 105 (or 110 if you need to add .chop to the gets to make your input work)

Run with command line flags pl.

r=/[#$_]/$_=(?1...gets).grep(r).slice_before{|e|-1>eval("#@l-"+@l=e)}.map{|a|a[9]?[a[0],'-->',a[-1]]:a}*' '


Convert the first input to a character class in a regex. Generate all numeric strings between 1 and the next input (exclusive) and find the ones that match the regex. slice_before trick is stolen from August to find contiguous ranges, it gets shorter by using an instance variable to remember the last element so I don't need each_cons, but longer since I'm working with strings. I check for ranges of size 10 or more by seeing whether they have a 10th element or not (a[9]), and replace their internal elements with the arrow.

## Perl - 170 162

$a=<>;chop$a;$a=~s/ /|/g;@b=grep{/$a/}(0..<>-1);while(++$c<@b){if($b[$c]-$b[$c-1]>1){($e=$c-$d)>9&&splice(@b,$d+1,$e-2,'-->')&&($c-=$e-3);$d=$c}}print join' ',@b


$a=<>; #Read digits chop$a;$a=~s/ /|/g; #Turn digit string into regex @b=grep{/$a/}(0..<>-1);    #Assign @b as list of numbers from 0 to second input which match the digits
while(++$c<@b){ #Loop$c through indexes of list
if($b[$c]-$b[$c-1]>1){    #If next number is not consecutive, do arrow adding stuff
($e=$c-$d)>9&& #If the number of previous consecutive numbers is at least 10 splice(@b,$d+1,$e-2,'-->')&& #Replace all but the first and last with '-->' ($c-=$e-3); #Subtract from index to compensate for decreased list length$d=$c #Set$d (fist index of consecutive range) to current index
}
}
print join' ',@b    #Print the list


# Python - 208 202 211

D=raw_input()
n=input()
s=[ifor i in range(n)if sum(d inifor d in D)]
i=0
while i<len(s):
j=len(s)
while j:
j-=1
try:
if int(s[j])-int(s[i])==j-i>8:s[i+1:j]=['-->']
except:1
i+=1
print' '.join(s)

• Doesn't this produce a wrong output formating? For me (Python 2.7) it outputs something like ['1', '2', '3']. – Emil Sep 23 '14 at 17:16
• @Emil: Sorry, fixed it. – Falko Sep 23 '14 at 20:58

# Bash+coreutils, 94 bytes

seq -s\  0 $[$1-1]|sed -r "s/\b[^ ${2// }]+\b/:/g s/([0-9]+)( [0-9]+){9,}/\1 -->\2/g s/: ?//g"  • seq generates all numbers below the maximum • The first sed line replaces any number not containing the interesting digits with : • The second sed line searches for runs of 10 or more space-separated numbers and replaces with start --> end • The final sed line removes unnecessary : and spaces. ### Output: $ ./belowdigits.sh 100 "1 3"
1 3 10 --> 19 21 23 30 --> 39 41 43 51 53 61 63 71 73 81 83 91 93
$./belowdigits.sh 29 "1 2 4 5 6 7" 1 2 4 5 6 7 10 --> 28$ ./belowdigits.sh 999999 "0 1 2 3 4 5 6 7 8 9"
0 --> 999998
$ ## Python, 227 Currently the longest, but whatever. a=raw_input().split() l=[i for i in range(input())if any(x in str(i)for x in a)] for i in l: for j in l[::-1]: try:L=l.index;l=l[:L(i)+1]+['-->']+l[L(j):]if j-i==L(j)-L(i)and j-i>8 else l except:1 print' '.join(map(str,l))  # Haskell, 195 194 main=interact$(\[d,m]->v$f(any(elemf(/=' ')d).s)[0..read m-1]).lines s=show f=filter v l@(x:m)|g l>x+8=unwords[s x,"->",s$g l,v$f(>g l)l]|0<1=s x++' ':v m v[]="" g s=f(notElems)[s!!0..]!!0-1  not very short but Imho quite good for this specific question and language. # Python 2, 202 191 Another try at Python, using the same idea as @August's Ruby solution: a=raw_input() s=[x for x in range(input())if any(c inxfor c in a)] for _,g in __import__('itertools').groupby(s,lambda x:x+1in s): l=map(str,g) print len(l)<9and' '.join(l)or l[0]+' -->',  PS: Coincidentally, the first two lines ended up nearly identical to both other Python entries. # R 224 w/o Comment a=as.character l=length x=a(scan()) # Read digits s=a(0:(scan()-1)) # Read max number p=as.numeric(s[Reduce(|,lapply(x,function(x)grepl(x,s)))])# Find all numbers we want j=1 # Print the arrow "-->" for (i in 1:l(z<-c(rle(diff(p))$l,1))){if(z[i]<9)cat(p[j:(j+z[i]-1)],"")else
cat(p[j],"-->","")
j=j+z[i]}


## PHP, 273258255248256239 234 bytes

What a mess.

### Submission:

function n($s,$b){$r=$q=$f="";for($g=-1;$g++<$b;){$i=0;foreach(explode(" ",$s)as$d){$i+=in_array($d,str_split($g));}if($i&&$b-$g){$q[]=$g;$f=$f?:$g;}elseif($f){$r.=($g-$f>9?$q[0]." --> ".($g-1):implode(" ",$q))." ";$q=$f="";}}echo$r;}


### Exploded view:

function n($s,$b) {
$r =$q = $f = ""; for ($g = -1; $g++ <$b;) {
$i = 0; foreach(explode(" ",$s) as $d) {$i += in_array($d, str_split($g));
}
if ($i &&$b-$g) {$q[] = $g;$f = $f ?:$g;
} elseif ($f){$r .= ($g-$f > 9 ? $q[0] . " --> " . ($g-1)
: implode(" ", $q) ) . " ";$q = $f = ""; } } echo$r;
}


### Variable explanations:

$b: string, upper bound (input) $s: string, digit string (input)
$d: int, individual digit in $s
$g: int, current guess $i: int, number of times a digit exists in the current guess
$f: int, first correct guess in a chain $q: array, correct guess queue
$r: string, final result (output) This is super unoptimized, still tweaking it. Edits: -18: Combining variable inits, merging two $i inits.
-7: Removing $a declaration. +8: Fixed two bugs: now allows 0 as output, now allows $b-1 and --> $b-1 as output. -17: God, I love ternary operators. -5: Let's treat $i as an int full-time, and simplify the resets.