Neutralize data

22

3

To neutralize data, recursively replace all numbers (not digits!) with zeros and all characters (not strings!) with spaces.

You must accept any single number, character, or string, or possibly recursive array* of mixed numeric/character data that your language can handle. For example, you must accept actual strings (and not restrict your input to lists of single characters) if your language can handle such.

If your language contains a built-in which does all or most of this task, I would appreciate an additional alternative version without it.

The shortest submission in each language is a winner, and will receive an upvote from me.

Sample cases

  1. """"

  2. 70

  3. 123.4560

  4. "X"" "

  5. " "" "

  6. "Yo!"" "

  7. [][]

  8. [-1.2E3][0]

  9. ["Hey"][" "]

  10. ["H","e","y"][" "," "," "]

  11. ["R",2,"D",2][" ",0," ",0]

  12. ["C","3","P",0][" "," "," ",0]

  13. ["THX",[1138]][" ",[0]]

  14. ["T","H","X",[1138]][" "," "," ",[0]]

  15. [[["H"],"e",1,1,0],[[-3],"arth"]][[[" "]," ",0,0,0],[[0]," "]]

* If your language has several types which can equally well represent arrays like the above examples, you may chose to support only one. Two entries can both win, even though they are using the same language, by each going with a different data type.

Adám

Posted 2017-01-16T09:44:45.540

Reputation: 37 779

What if our language doesn't distinguish between characters and length-1 strings? – xnor – 2017-01-16T09:48:05.170

@xnor AFAICT the effect would be the same. – Adám – 2017-01-16T09:52:26.237

Oh, I see that now from the test cases, but it wasn't clear to me that meant to take every string element and replace each of its characters with spaces. Actually, I didn't interpret that the replacements have to be done recursively at all. The spec talks about neutralizing an array, but it looks like you want single elements not in an array to be acted on as well? – xnor – 2017-01-16T09:54:37.560

@xnor Correct. Feel free to edit the question to better reflect this. – Adám – 2017-01-16T09:58:04.087

Let us continue this discussion in chat.

– Adám – 2017-01-16T10:53:33.627

What if our language doesn't distinguish between numbers and strings of digits? – DLosc – 2017-01-16T18:54:00.267

Also, what about languages that don't have a string or character data type? Can they just replace the numbers, or are they disallowed for this challenge? – DLosc – 2017-01-16T18:55:23.167

@DLosc Not disallowed, but rather pointless. I suppose this either isn't a production grade language or is a very old language. Feel free to submit anyway. – Adám – 2017-01-16T19:03:36.870

Answers

17

JavaScript (ES6), 53 47 bytes

f=o=>o.big?o.replace(/./g,' '):o.map?o.map(f):0

Test cases

f=o=>o.big?o.replace(/./g,' '):o.map?o.map(f):0

test = [
  "",
  7,
  123.456,
  "X",
  "  ",
  "Yo!",
  [],
  [-1.2E3],
  ["Hey"],
  ["H","e","y"],
  ["R",2,"D",2],
  ["C","3","P",0],
  ["THX",[1138]],
  ["T","H","X",[1138]],
  [[["H"],"e",1,1,0],[[-3],"arth"]]
];

test.map(o => {
  console.log(JSON.stringify(o), '=>', JSON.stringify(f(o)));
});

Arnauld

Posted 2017-01-16T09:44:45.540

Reputation: 111 334

Finally, a use for big()! Although, you'd probably provide better future-proofing using raw() instead. – Shaggy – 2017-05-16T12:02:11.620

@Shaggy Hmm. Which syntax would you use with raw()? I don't think String.prototype.raw() is defined. Only String.raw() is. – Arnauld – 2017-05-16T13:21:45.960

Oh, yeah, sorry. – Shaggy – 2017-05-16T13:22:37.650

7

Ruby, 54 53 49 bytes

f=->a{a*0==0?0:a*0==[]?a.map{|x|f[x]}:" "*a.size}

Maybe there is a better way, but:

  • x*0 == 0 for integers
  • x*0 == "" for strings
  • x*0 == [] for arrays

G B

Posted 2017-01-16T09:44:45.540

Reputation: 11 099

Clever! Thanks for giving me a way to determine types in Python as well! – TidB – 2017-01-16T14:37:49.583

it doesn't work for the string and number examples outside of an array, but if you change a.map to [*a].map it works as expected – Alexis Andersen – 2017-01-17T20:20:03.710

This has been fixed now, thanks. – G B – 2017-01-18T07:57:25.820

7

Python 2, 52 bytes

f=lambda x:1-(x<{})and map(f,x)if x<''else' '*len(x)

Try it online!

How it works

Python lets you compare different types. Numeric types are always smaller than iterables, and iterables are sorted by their type names, so

0 < {} < [] < '' < ()

This way, f does the following.

  • If x is numeric x<{} returns True and 1-(x<{}) returns 0. The code after and does not get executed.

  • If x is iterable, 1-(x<{}) returns 1 (truthy), so the code after and gets executed.

    • If x is a list, x<'' is true and f gets mapped over its items.

    • If x is a string, x<'' is false and x is replaced with a string of spaces of the same length.

Dennis

Posted 2017-01-16T09:44:45.540

Reputation: 196 637

6

Mathematica, 51 bytes

I've currently got two solutions at this byte count:

#/._?NumberQ->0/.x_String:>StringReplace[x,_->" "]&
StringReplace[#,_->" "]~Check~#&//@#/._?NumberQ->0&

The second one throws a bunch of warnings which can be ignored.

Explanation

In either case, we start by turning numbers into zeros with

#/._?NumberQ->0

Then to process the string, there are two options. Either, we use another substitution that only applies to strings:

.../.x_String:>StringReplace[x,_->" "]

Or, we use the MapAll operator //@ which maps a function over every single element in a nested list. The catch here is that we'll be trying to use StringReplace on zeros as well as the symbol List (since //@ also goes through the heads of expressions), so we need to use Check (sort of like a catch statement in other languages) to avoid wreaking havoc with those values:

StringReplace[#,_->" "]~Check~#&//@...

Martin Ender

Posted 2017-01-16T09:44:45.540

Reputation: 184 808

5

Perl 6, 34 48 bytes

{.deepmap:{$_~~Str??" "x.comb!!0}}

{$_~~List??$_».&?BLOCK!!$_~~Str??" "x .comb!!0}

Expanded:

{                          # block-based lambda
    $_ ~~ List             # if argument is a list/array
        ?? $_».&?BLOCK     # then recurse for each element (&?BLOCK is a compile-time var)
        !! $_ ~~ Str       # else if argument is a string
            ?? " "x .comb  # then use space repeated by the string's length,
            !! 0           # else use the number 0
}

smls

Posted 2017-01-16T09:44:45.540

Reputation: 4 352

The .deepmap doesn't work correctly for singular inputs like "X" or 7, because it always returns a List. – Brad Gilbert b2gills – 2017-01-16T16:22:56.847

Darn, I must have overlooked that (or the task was clarified later). This makes it quite a bit longer. – smls – 2017-01-17T07:06:20.130

5

Jelly, 4 bytes

nOa⁶

This is a monadic link. Jelly's implicit printing does a lot of splatting; to verify that the output is what it should be, you can view the internal representation with ŒṘ. Note that this exposes strings as lists of characters, which is how the Jelly interpreter implements them.

Try it online!

How it works

nOa⁶  Monadic link. Argument: z

 O    Ordinal; replace all characters with the code points.
      This does not affect numbers.
n     Vectorizing not-equal; compare z with the result to the right, replacing
      characters with 1 and numbers with 0.
  a⁶  Logical AND space; replace all 1's with spaces.

Dennis

Posted 2017-01-16T09:44:45.540

Reputation: 196 637

I was waiting for an APL to come up. Now chose a different one for a 1-byte solution! – Adám – 2017-01-16T17:53:22.630

Thanks for the heads up, but I'm not sure I even know how to represent [[["H"],"e",1,1,0],[[-3],"arth"]] in APL... – Dennis – 2017-01-16T18:50:46.807

JSON2APLexpr←⎕SE.Dyalog.Utils.repObj 7159⌶ ⋄ JSON2APLexpr'[[["H"],"e",1,1,0],[[-3],"arth"]]' gives ((,⊂,'H') (,'e') 1 1 0) ((,¯3) 'arth'). FYI, 7159⌶ will be ⎕JSON in version 16.0. – Adám – 2017-01-16T18:57:37.743

APL can tackle any JSON. However, plenty of APL data cannot be unambiguously represented in JSON. – Adám – 2017-01-16T18:59:43.473

Do you think a code-golf which involves parsing or maybe manipulating APL arrays would be interesting? – Adám – 2017-01-17T09:44:18.463

@Adám As long as you can make the question self-contained, that should be rather interesting. I did something similar for Jelly once: Jam don't add like that

– Dennis – 2017-01-17T12:38:46.917

3

GAP, 91 bytes

GAP has a method Zero that returns the neutral additive element corresponding to an element of an additive structure. That handles numbers and even lists of numbers which are considered vectors, but not arbitrary lists. So let's add these and Chars and use that Strings are lists of Chars:

InstallOtherMethod(Zero,[IsChar],c->' ');
InstallOtherMethod(Zero,[IsList],l->List(l,Zero));

(I'm not counting the newline as it isn't needed.) Of course this is far away from the intended use of Zero, and GAP would complain if I hadn't used InstallOtherMethod. Now I can do:

gap> Zero([[["H"],"e",1,1,0],[[-3],"arth"]]);
[ [ [ " " ], " ", 0, 0, 0 ], [ [ 0 ], "    " ] ]

I wouldn't say that the builtin does most of the job, one might rather suspect that writing a normal function should be shorter, but my best try doing that was 92 bytes long:

f:=function(x)if IsInt(x)then return 0;elif IsList(x)then return List(x,f);fi;return' ';end;

Christian Sievers

Posted 2017-01-16T09:44:45.540

Reputation: 6 366

2

Haskell, 115 bytes

My language cannot handle any mix of numbers and strings in lists (but of course you can define a sum type and put that in a list), and its standard lists cannot handle differently nested lists. So I'm just doing what it can handle. I think that is not unfair because it is still long, and I mainly do it to show features of haskell that are rarely seen in haskell golfing solutions. Note that Strings are lists of Chars.

class N a where n::a->a
instance N Double where n _=0
instance N Char where n _=' '
instance N a=>N[a]where n=map n

This handles any number as Double:

*Main> n 42
0.0
*Main> n 123.456
0.0
*Main> n "hi"
"  "
*Main> n [[1,2],[3,4,5]]
[[0.0,0.0],[0.0,0.0,0.0]]
*Main> n ["hello","world!"]
["     ","      "]

Christian Sievers

Posted 2017-01-16T09:44:45.540

Reputation: 6 366

1It should be shorter to define a data structure with data N=S[Char]|I Int|L[N] and a recursive function on that. – Zgarb – 2017-01-16T12:35:01.213

You're probably right I guess, but that's less interesting and still looks like not really solving the problem (I admit it actually is closer). I'll leave that for someone else. – Christian Sievers – 2017-01-16T12:53:58.293

integers? How about test case 3.? – Adám – 2017-01-16T12:57:14.513

@Adám Oh you're right, and unfortunately I can't claim my language doesn't have those. Can I only handle Doubles? I can input them without decimal point. – Christian Sievers – 2017-01-16T13:21:12.863

@ChristianSievers Yes, that's fine. Basically, you should be able to handle whatever an import (if possible) from the given JSON would give you. – Adám – 2017-01-16T13:22:37.017

2

PHP, 91 bytes

function f($a){return!is_array($a)?is_string($a)?str_pad("",strlen($a)):0:array_map(f,$a);}

if parameter is array: recurse using array_map.
else if parameter is string: generate a strings of spaces with the same length.
else 0.

is_string saves one byte over is_numeric; negating is_array() renders parentheses obsolete. Altogether it´s 17 bytes shorter than if()recursion-loop;else x?string:number with a call by reference.

Titus

Posted 2017-01-16T09:44:45.540

Reputation: 13 814

2

Python 2, 59 bytes

g=lambda d:0if d*0==0else " "*len(d)if d*0==""else map(g,d)

uses G B's way to determine types

ovs

Posted 2017-01-16T09:44:45.540

Reputation: 21 408

2

 Common Lisp, 87

(defun c(e)(typecase e(list(mapcar'c e))(number 0)(string(map'string(lambda(u)#\ )e))))

Ungolfed

(defun c(e)
  (typecase e
    (list (mapcar #'c e))
    (number 0)
    (string (map 'string (lambda(u) #\space) e))))

Example

> (c '((("H") "e" 1 1 0) ((-3) "arth")))
(((" ") " " 0 0 0) ((0) "    "))

coredump

Posted 2017-01-16T09:44:45.540

Reputation: 6 292

1

Groovy, 53 bytes

{[it].collectNested{it in String?" "*it.size():0}[0]}

This is an unnamed closure. Try it here!

Explanation:

Groovy has this method .collectNested which helps to iterate through a list as if it was flattened.

To handle special cases where only an integer or a string is passed without a list, simply wrap every input into a list and output the first element.

Gurupad Mamadapur

Posted 2017-01-16T09:44:45.540

Reputation: 1 791

1

Pyke, 8 bytes (Old version)

.FZ*0+d&

Explanation:

.FZ*0+d& - for i in deep_for(input):
  Z*     -    i*0
    0+   -   ^ + 0
      d& -  ^ and " "

This no longer works as an update made it so falsies of other types where there are truthies automatically convert to the falsey of the truthy type.

Blue

Posted 2017-01-16T09:44:45.540

Reputation: 26 661

That's of course acceptable. – Adám – 2017-01-16T18:47:04.607

1

C#, 197 195 Bytes

a=>{if(a is string||a is char)return new string(' ',(a as string)?.Length??1);try{System.Convert.ToDecimal(a);return 0;}catch{}var b=(object[])a;for(int i=0;i<b.Length;)b[i]=n(b[i++]);return b;};

This function handles char, string, any builtin number type and recursive arrays.

Full program, ungolfed whit output helper:

using System.Linq;    
class Class
{
    public static void Main()
    {
        System.Func<object, object> n = null;
        n = a => 
        {
            if (a is string || a is char)
                return new string(' ', (a as string)?.Length ?? 1);
            try
            {
                System.Convert.ToDecimal(a);
                return 0;
            }
            catch { }

            var b = (object[])a;
            for (int i = 0; i < b.Length;)
                b[i] = n(b[i++]);
            return b;
        };

        var result = n(new object[] { new object[] { new object[] { "H" }, 'e', 1.5, 1, 0 }, new object[] { new object[] { -3 }, "arth" } });
        System.Console.WriteLine(Output(result));
        System.Console.Read();
    }

    static string Output(object x)
    {
        var arr = x as object[];
        if (arr != null)
            return "[" + string.Join(",", arr.Select(Output)) + "]";
        else
            return x.ToString();
    }
};

The using statement is only needed for the output helper, not for the actual function.

Try Online

raznagul

Posted 2017-01-16T09:44:45.540

Reputation: 424

1

APL (Dyalog) 13.2 and earlier, 1 byte

Until and including version 13.2, monadic did exactly this. The old behaviour can be activated by setting ⎕ML (Migration Level) to zero.

Try it online!

Without using old behaviour it is 4 bytes:

⊃0⍴⊂

Try it online!

 enclose

0⍴ make a length-zero list of copies of the entire input (preserves only structure and type info)

 coerce one element from that (creates a prototypical array)

Adám

Posted 2017-01-16T09:44:45.540

Reputation: 37 779

0

Javascript ES6, 81 chars

f=(x,t)=>(t=g=>eval(`try{x.${g}}catch(e){}`))`replace(/./g,' ')`||t`map(f)`||x&&0

Test:

f=(x,t)=>(t=g=>eval(`try{x.${g}}catch(e){}`))`replace(/./g,' ')`||t`map(f)`||x&&0

console.log(
`"" → ""
7 → 0
123.456 → 0
"X" → " "
"  " → "  "
"Yo!" → "   "
[] → []
[-1.2E3] → [0]
["Hey"] → ["   "]
["H","e","y"] → [" "," "," "]
["R",2,"D",2] → [" ",0," ",0]
["C","3","P",0] → [" "," "," ",0]
["THX",[1138]] → ["   ",[0]]
["T","H","X",[1138]] → [" "," "," ",[0]]
[[["H"],"e",1,1,0],[[-3],"arth"]] → [[[" "]," ",0,0,0],[[0],"    "]]`
.split`
`.map(s => s.split` → `.map(eval))
.every(([s,k]) => JSON.stringify(f(s))==JSON.stringify(k)))

Qwertiy

Posted 2017-01-16T09:44:45.540

Reputation: 2 697

0

Java 7, 262 (268) bytes

import java.util.*;Object c(Object o){if(o instanceof List){List r=new ArrayList();for(Object x:(List)o)r.add(c(x));return r;}if(o instanceof String){String r="\"";for(int i=((String)o).length();i-->0;r+=" ");return r+"\"";}return o instanceof Number?0:o instanceof Character?"' '":"";}

282 + 6 for the added \" and ' to pretty-print the String and characters.

Explanation:

import java.util.*;            // Required import for List and ArrayList
Object c(Object o){            // Method with Object parameter and Object return-type
  if(o instanceof List){       //  If the input is a List
    List r=new ArrayList();    //   Create a result-list
    for(Object x:(List)o)      //   Loop over the items of the input-list
      r.add(c(x));             //    And add all items with a recursive-call to this method
                               //   End of loop (implicit / single-line body)
    return r;                  //   Return result-list
  }if(o instanceof String){    //  If the input is a String instead
    String r="\"";             //   Create a result-String (starting with `"`
    for(int i=((String)o).length();i-->0;r+=" ");
                               //   Replace all characters in the String with a space
    return r+"\"";             //   Return the result within double-quotes
  }
  return o instanceof Number?  //  If the input is an integer or decimal instead:
    0                          //   Return 0
   :o instanceof Character?    //  If the input is a character instead:
    "' '"                      //   Return ' '
   :                           //  Else:
    "";                        //   Return an empty String
}                              // End of method

Test code:

Try it here.

import java.util.*;
class M{
  static Object c(Object o){if(o instanceof List){List r=new ArrayList();for(Object x:(List)o)r.add(c(x));return r;}if(o instanceof String){String r="\"";for(int i=((String)o).length();i-->0;r+=" ");return r+"\"";}return o instanceof Number?0:o instanceof Character?"' '":"";}

  public static void main(String[] a){
    System.out.println(c(""));
    System.out.println(c(7));
    System.out.println(c(123.456));
    System.out.println(c('X'));
    System.out.println(c("  "));
    System.out.println(c("Yo!"));
    System.out.println(c(new ArrayList()));
    System.out.println(c(new ArrayList(){{add(-1.2e3);}}));
    System.out.println(c(new ArrayList(){{add("Hey");}}));
    System.out.println(c(new ArrayList(){{add('H');add('e');add('y');}}));
    System.out.println(c(new ArrayList(){{add('R');add(2);add('D');add(2);}}));
    System.out.println(c(new ArrayList(){{add("THX");add(new ArrayList(){{add(1138);}});}}));
    System.out.println(c(new ArrayList(){{add('T');add('H');add('X');add(new ArrayList(){{add(1138);}});}}));
    System.out.println(c(new ArrayList(){{add(new ArrayList(){{add(new ArrayList(){{add('H');}});add('e');add(1);add(1);add(0);}});add(new ArrayList(){{add(new ArrayList(){{add(-3);}});add("arth");}});}}));
  }
}

Output:

""
0
0
' '
"  "
"   "
[]
[0]
["   "]
[' ', ' ', ' ']
[' ', 0, ' ', 0]
["   ", [0]]
[' ', ' ', ' ', [0]]
[[[' '], ' ', 0, 0, 0], [[0], "    "]]

Kevin Cruijssen

Posted 2017-01-16T09:44:45.540

Reputation: 67 575