Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Toy Problem of the Week

Name: Anonymous 2009-12-12 18:22

I was raking around on the net and found this problem and coded up a solution. Once we get at least 10 solutions I'll post mine and a link to where I found the problem.
Any language, any libraries (but declare them) allowed. Aim for clarity and conciseness. Assume the input is well formed. Mine is 5 lines of scheme code (6 if we include requiring a library). No calling an "answer" function that "you wrote already and put in an external lib" ;)

Consider the problem of turning a list consisting
of a mix between symbols and non-symbols into a
list of lists of the symbol and its following
non-symbols. That is:

Input:    ({<symbol> <non-symbol>*} ... )
Output:   ((<symbol> (<non-symbol>*)) ...)
Example:     (a 1 2 3 b 4 5 c d 8 9 e)
           -> ((a (1 2 3)) (b (4 5)) (c ()) (d (8 9)) (e ()))

Name: Anonymous 2009-12-13 1:09

One line of actual code does the job:

import Data.List (groupBy)

f :: (String -> Bool) -> [String] -> [[String]]
f isSymbol = groupBy (const $ not . isSymbol)


Given a predicate that determines whether a string is a symbol or not, ``f'' produces the desired function.

Example:

GHCi> -- We define a symbol to be a string that does not begin with a digit.
GHCi> -- For the sake of simplicity, all strings are assumed to be non-empty.
GHCi> let isSymbol = (`notElem` ['0'..'9']) . head
GHCi> -- Let's test it.
GHCi> (isSymbol "foo", isSymbol "3bar")
(True,False)
GHCi> -- Finally, we test f.
GHCi> f isSymbol ["a", "1", "2", "3", "b", "4", "5", "c", "d", "8", "9", "e"]
[["a","1","2","3"],["b","4","5"],["c"],["d","8","9"],["e"]]


Now, due to the fact that Haskell's lists are homogenous, the output format is slightly different from the one specified in >>1. We can alter f to return tuples instead:

f :: (String -> Bool) -> [String] -> [(String, [String])]
f isSymbol = map (\ (s : ns) -> (s, ns)) . groupBy (const $ not . isSymbol)


And we get:

GHCi> f isSymbol ["a", "1", "2", "3", "b", "4", "5", "c", "d", "8", "9", "e"]
[("a",["1","2","3"]),("b",["4","5"]),("c",[]),("d",["8","9"]),("e",[])]

Name: 41 2009-12-13 1:21

And of course, constraining this function to Strings is quite pointless. The same code will work with the more general type signature (a -> Bool) -> [a] -> [(a, [a])].

Name: 13 2009-12-13 2:59

Thanks >>41, your post gave me an idea on how to write this a lot more concisely:

(asdf:oos 'asdf:load-op :split-sequence)
(use-package :split-sequence)

(defun group-by (sequence &optional (predicate #'symbolp)) 
  (let ((numbers (rest (split-sequence-if predicate sequence)))
        (symbols (remove-if-not predicate sequence)))
    (mapcar #'list symbols numbers)))
;CL-USER> (group-by '(a 1 2 3 b 4 5 c d 8 9 e))
;((A (1 2 3)) (B (4 5)) (C NIL) (D (8 9)) (E NIL))


Only 4 lines of code for the entire function!

Name: Anonymous 2009-12-13 13:17

t=[:a,1,2,3,:b,4,5,:c,:d,8,9,:e]
f=proc{|x|x.inject([]){|a,e|e.is_a?(Symbol)?a<<[e,[]]:a[-1][-1]<<e;a}}
p f.call(t)


Only 1 line of pure beauty.

Name: Anonymous 2009-12-13 17:12

I am sorry, I must have missed something obvious, but how do we know that '1' is not also a symbol? You need a symbol table to correctly solve this problem, it seems to me. It seems unspecified what, exactly, a symbol is.

/prog/ fail

Name: Anonymous 2009-12-13 17:53

>>45
OP already mentioned that he meant Lisp-like symbols:
1, "1" or '|1| are very different kinds of objects, one is the integer 1, the other is a string containg the character #\1, and the other is a symbol named by the string "1". Things may be slightly different in Scheme, but 1 and '1' are different things. OP's problems essentially boils down to grouping down objects given a predicate which separates the objects into 2 disjoint groups, the actual meaning of symbols or non-symbols is not as relevant, sadly, at least some half of the solutions are string-based, so they miss the point of the problem, and work with some limited amount of input.

Name: Anonymous 2009-12-13 21:13

This is my first non-trivial algorithm in F#. Gosh, this is hard.

let rec splitlist l along =   

    let rec gather l =
        match l with
            |[] -> []
            |head::tail when (head<>along) -> head::(gather tail)
            |head::tail -> []

    match l with
        |[] -> []
        |head::tail when (head=along) -> (head::(gather tail))::(splitlist tail along)           
        |head::tail -> (splitlist tail along)
       
       
let separate l along=
    (splitlist l along) |> Seq.map (fun x -> match x with |head::tail -> (head ,tail))

Name: Anonymous 2009-12-13 21:19

>>47

Forgot to mention that it only splits along one value, not a set of values.

Name: Anonymous 2009-12-13 21:56

>>46
Then I'd guess the symbol? predicate is good enough.
(define toy
  (λ(lst)
    (let ((collector (λ(x y) (if (symbol? x)
                                 (cons (list x) y)
                                 (cons (append (first y) (list x)) (rest y))))))
      (map (λ(x) (list (first x) (list* (rest x)))) (reverse (foldl collector empty lst))))))

(toy '(a 1 2 3 b 4 5 c d 8 9 e))
((a (1 2 3)) (b (4 5)) (c ()) (d (8 9)) (e ()))
>

Name: Anonymous 2009-12-14 7:03

>>47
first non-trivial algorithm
non-trivial
( ≖‿≖)

Name: Anonymous 2009-12-14 8:36

>>50

Oh I'm probably talking to an ELITE H4XX0R PROGRAMMER excuse me.

Name: Anonymous 2009-12-14 10:46

hibt?

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List