31
\$\begingroup\$

Introduction and Credit

We all know and love our awesome rules to test whether a number is divisble by 11 or 3, which is just some clever sum over the digits of the number. Now this challenge takes this to a new level, by requiring you to compute the sum of the digits and then checking whether the result is a perfect integer square, neither of which operations usually can be done very short. As this property is also very hard to see when looking at a number, we want this to be done for entire lists of numbers so we can save human work. So this is your challenge now!

This was an assignment at my university functional programming course. This assignment is now closed and has been discussed in class and I have my professor's permission to post it here (I asked explicitely).

Specification

Input

Your input is a list of non-negative integers, in any standard I/O format.
You may choose the list format as your language needs it

Output

The output is a list of integers, in any standard I/O format.

What to do?

Filter out every integer from the input list for which the sum of the digits is not a a square (of an integer).
The order of the elements may not be changed, e.g. if you get [1,5,9] you may not return [9,1]

Potential corner cases

0 is a non-negative integer and thus a valid input and 0 is also a valid integer root, e.g. 0 counts as an integer square.
The empty list is a valid input and output as well.

Who wins?

This is code-golf so the shortest answer in bytes wins!
Standard rules apply of course.

Test Cases

[1,4,9,16,25,1111] -> [1,4,9,1111]
[1431,2,0,22,999999999] -> [1431,0,22,999999999]
[22228,4,113125,22345] -> [22228,4,22345]
[] -> []
[421337,99,123456789,1133557799] -> []

Step-by-Step Example

Example input: [1337,4444]
Handling first number:
Sum of the digits of 1337: 1+3+3+7=14
14 is not an integer square, thus will be dropped!
Handling second number:
Sum of the digits of 4444: 4+4+4+4=16
16 is an integer square because 4*4=16, can get into the output list!
Example output: [4444]
\$\endgroup\$
  • 11
    \$\begingroup\$ Nice first challenge, and welcome to the site! \$\endgroup\$ – DJMcMayhem Jun 10 '16 at 14:14
  • \$\begingroup\$ For future challenges note the sandbox. It's a place where we put challenges before we put them on the main site so hey can get reviewed and their content queried so they will (hopefully) get better received on main. Not that this is a bad question though (I actually quite like it) \$\endgroup\$ – Blue Jun 10 '16 at 14:16
  • \$\begingroup\$ @muddyfish, I've read about this and considered posting there but decided not to do it, because I was confident, that there's nothing I could miss / do horribly wrong here :) Of course if I have even some doubt there could be something I miss I'll post there. \$\endgroup\$ – SEJPM Jun 10 '16 at 14:21
  • 12
    \$\begingroup\$ While it is totally fine to avoid the sandbox, had you posted there I would have suggested that you make the challenge only about testing an individual integer. The interesting task is the test, wrapping that task with a filter isn't particularly interesting. All it seems to do is make the challenge substantially more difficult in esoteric languages that do not have arrays as types. That may sound a bit harsh, but this is still an excellent first post. Just saying that the sandbox is there because no matter how sure you are you didn't miss anything, you missed something. \$\endgroup\$ – FryAmTheEggman Jun 10 '16 at 14:29
  • 1
    \$\begingroup\$ @FryAmTheEggman I can say for Mathematica that making this function listable complicates things in a slightly non-trivial way, so it's not exactly boring. \$\endgroup\$ – LLlAMnYP Jun 17 '16 at 13:42

42 Answers 42

0
\$\begingroup\$

q - 53 characters

{x where({(sum({"J"$x}')($:)x)in((!:)x+1)*(!:)x+1}')x}

The interesting bit is the inner lambda, which casts to a string, sums the digit (by casting each of them to an int), and then checks if they are a in a list of squares.

\$\endgroup\$
  • \$\begingroup\$ {x where s=floor s:sqrt sum each value@''string x} for 50 without any shorthand, or {x(&)s=(_)s:sqrt sum@'(.:)@''($)x} for 34. \$\endgroup\$ – streetster Aug 28 '18 at 20:51
0
\$\begingroup\$

Javascript, 61 65

f=
a=>a.filter(x=>(r=Math.sqrt(eval([...`${x}`].join`+`)))==~~r)

j=JSON.stringify;
console.log([
[1,4,9,16,25,1111],
[1431,2,0,22,999999999],
[22228,4,113125,22345],
[],
[421337,99,123456789,1133557799]
].map(x=>j(x)+' -> '+j(f(x))).join`
`)

\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES7), 56 bytes

a=>a.filter(n=>[...''+n].reduce((x,y)=>+x+ +y)**.5%1==0)
\$\endgroup\$
0
\$\begingroup\$

C#, 103 bytes

int[] f(int[] a){return a.Where(n=>Math.Sqrt((n+"").Select(m=>int.Parse(m+"")).Sum())%1==0).ToArray();}

Its really sad i have to turn chars and ints into strings all the time to work on them, i wish there was a better solution than adding an empty literal "" to cast into string.

any help on golfing this down appreciated

\$\endgroup\$
0
\$\begingroup\$

Hoon, 78 bytes

|*
*
%+
skim
+<
|=
@ui
=(0 q:(sqt (roll (scan (slag 2 <+<>) (star dit)) add)))

++skim only keeps the elements of the list that the function returns yes for. We cast all the atoms in the list to @ui in the sample, for the sole reason that Urbit's integers have mandatory group seperators: if you try to cast 1.000 to a string, it will return "1.000" instead of "1000". <@ui1.000>, however, gives "0i1000", so we cast and then cut off the first two letters of the string.

We then parse the string with the parser combinator (star dit), which is like the [0-9]* regex but also converts the character to an atom. We fold over the resulting list with add.

We call sqt on the number. In Hoon, the only data types are atoms or tuples, so it returns two atoms intead of a float: the nearest perfect square root, and the remainder. We can then just test if the remainder is 0.

\$\endgroup\$
0
\$\begingroup\$

TXR Lisp: 85 81 72 byte (op ...) denoting anon. function:

(op keep-if (opip tostring (mapcar chr-digit) (apply +) (= @1 [[dup *] (isqrt @1)])))
(op keep-if (opip `@1` (mapcar chr-digit) (apply +) (= @1 [[dup *] (isqrt @1)])))
(op keep-if(opip`@1`(mapcar chr-digit)(apply +)(=@1[[dup *](isqrt@1)])))
$ txr -i
1> (op keep-if(opip`@1`(mapcar chr-digit)(apply +)(=@1[[dup *](isqrt@1)])))
#<interpreted fun: lambda #:rest-0117>
2> [*1 '(1 4 9 16 25 1111)]
(1 4 9 1111)
3> [*1 '(1431 2 0 22 999999999)]
(1431 0 22 999999999)
4> [*1 ()]
nil
5> [*1 '(22228 4 113125 22345)]
(22228 4 22345)
6> [*1 '(421337 99 123456789 1133557799)]
nil
7> 

isqrt is integer square root. This will handle large integers; no floating-point hacks here.

TXR Lisp is fundamentally a Lisp-2 dialect, like ANSI Common Lisp or Emacs Lisp. However, the square brackets [whatever ...] notation is syntactic sugar for the operator (dwim whatever ...) which evaluates using a form of Lisp-1 namespace semantics rather than Lisp-2: functions and variable bindings in one space rather than separate spaces. dwim is "deep"; it's not a macro transforming Lisp-2 to Lisp-2; it has visibility into the lexical environments to deliver the actual Lisp-1-like semantics.

In [dup *], the dup combinator takes a binary function (or a function that can be used as binary), and returns a unary function which applies two copies of its argument to that function as two arguments; i.e [dup *] denotes a squaring function.

op is a rich partial evaluation macro, and opip combines left-to-right pipeline with op: op pipe. (op mapcar +) curries the mapcar function. In (opip (mapcar +) ...),mapcaris similarly curried (theop` is implicit), and part of a pipeline.

The TXR Lisp REPL allows numbered references to prior results, modulo 100: *1 is the value produced in the most recent command line numbered 1, or 101, or 201, ...

\$\endgroup\$
0
\$\begingroup\$

C: 113 111 — based on other C answer.

This is a complete program with main. The input list is the argument list.

Old style C is used, but with the C99 fmod function.

q(char*n){double m=0;while(*n)m+=*n++-48;return!fmod(sqrt(m),1);}main(c,v)char**v;{while(*++v)if(q(*v))puts(*v);}
q(char*n){double m=0;while(*n)m+=*n++-48;return!fmod(sqrt(m),1);}main(c,v)char**v;{while(*++v)q(*v)&&puts(*v);}

Run:

$ gcc golf.c -o golf -lm
golf.c:1:1: warning: data definition has no type or storage class [enabled by default]
golf.c: In function ‘q’:
golf.c:1:52: warning: incompatible implicit declaration of built-in function ‘fmod’ [enabled by default]
golf.c:1:57: warning: incompatible implicit declaration of built-in function ‘sqrt’ [enabled by default]
$ ./golf 1 4 9 16 25 1111
1
4
9
1111
$ ./golf
$ ./golf 421337 99 123456 1133557799
$
\$\endgroup\$
0
\$\begingroup\$

Actually, 12 bytes

`$♂≈Σ;√≈²=`░

Try it online!

Explanation:

`$♂≈Σ;√≈²=`░
`$♂≈Σ;√≈²=`░  filter list, taking only values where the following function is true:
 $♂≈Σ           to string, map int, sum (digital sum, we'll call this n)
     ;√≈²=      compare equality to int(sqrt(n))**2
\$\endgroup\$
0
\$\begingroup\$

Neim, 4 bytes

Λ𝐬q𝕚

Explanation:

Λ    Keep if
 𝐬   sum of digits
   𝕚 is in
  q  square numbers

Try it online!

\$\endgroup\$
0
\$\begingroup\$

F#, 95 bytes

let s n=Seq.exists(fun x->x*x=n){1..n}
let i x=Seq.filter(string>>Seq.sumBy(int>>(+)(-48))>>s)x

Try it online!

Makes a lot of use of the >> operator (the function composition operator) which chains functions together. s determines if there is an integer square for n.

The main function i maps each number into a string, then sums the digits in the string. Each digit is the character's integer representation minus 48 (e.g. '4' |> int = 52 - 48 = 4). Then it uses s to determine if the digit sums has an integer square. If it does, it's included in the returned sequence. If it does not, then it's excluded (Seq.filter).

\$\endgroup\$
0
\$\begingroup\$

Attache, 18 bytes

`\&:(IsSquare@Sum)

Try it online!

Explanation

`\ is the filter operator and &: applies the function IsSquare@Sum as it's predicate.

\$\endgroup\$
0
\$\begingroup\$

Japt, 8 bytes

f_õ²øZìx

Try it

f_ìx ¬v1

Try it

\$\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.