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

Pages: 1-4041-

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: !u/EiCHERRY 2009-12-12 18:25

i can't.
haskells lists are homogen.

Name: Anonymous 2009-12-12 18:26

(()())())(((((((((((((((((((((()))))))))())))()(no-fun))))))))))))))))()())))))))))))))))((((((((((()))))))()()()()()))))))))))((((((())))()lambda()()))))))))))))))))))))))))((((()))))()))))))))(((((((((())))))))())))))))))))))))
the answer in lisp

Name: Anonymous 2009-12-12 18:28

>>2
That is a good point, how about a very large tuple ;) Alternatively, you could treat the symbols as strings i.e. ["a", "1", "2", "3", "b", "4", "5", "c", "d", "8", "9", "e"]

Name: Anonymous 2009-12-12 18:29

>>1
Is the input supposed to be correct?
Is the code supposed to check it for correctness?

Name: Anonymous 2009-12-12 18:30

>>5
Assume the input is well formed.
You assume the input is always correct.

Name: Anonymous 2009-12-12 18:41


sub doIt{
    my @ret;
    for(@_){
        /[a-z]+/i and push (@ret, [$_, []]), next;
        /\d/ and push @{$ret[-1]->[1]}, $_;
    }
    @ret;
}

Name: Anonymous 2009-12-12 18:44

>>7
Valid Perl Code

Name: Anonymous 2009-12-12 18:49


sub doIt{
    my @ret;
    for(@_){
        /^[a-z]+$/i and push (@ret, [$_, []]), next;
        /^\d+$/ and push @{$ret[-1]->[1]}, $_;
    }
    @ret;
}

tweaked it a bit.
and, as you see i only look at a-z as symbols. maybe you want something other, but meh.

Name: Anonymous 2009-12-12 19:10

ENTERPRISE SED SOLUTION


1 {
  s/\([a-z]\)/(\1/g
  s/\([a-z]\) \([0-9]\)/\1 (\2/g
  s/\([0-9]\) (\([a-z]\)/\1)) (\2/g
  s/\([0-9]\))$/\1))/g
  s/\([a-z]\) (\([a-z]\)/\1 ()) (\2/g
  s/\([a-z]\))$/\1 ())/g
}

Name: Anonymous 2009-12-12 19:27

class Array
  def foo
    map{|x|"|#{x}"}.join.scan(/\|([^\|]+)((\|\d+)*)/).map{|x,y,z|[x,y==""?[]:y[1..y.size].split("|").map{|x|x.to_i}]}
  end
end

Name: Anonymous 2009-12-12 19:29

["a",1,2,3,"b",4,5,"c","d",8,9,"e"].foo

Name: Anonymous 2009-12-12 20:01

Here's my line-noise version in CL:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (dolist (system '(:meta :arnesi))
    (asdf:oos 'asdf:load-op system)))

(defpackage :toy-problems
  (:use :cl :meta)
  (:import-from :arnesi "WITH-COLLECTOR" "MAKE-COLLECTOR"))

(in-package :toy-problems)
(eval-when (:compile-toplevel :load-toplevel :execute)
  (enable-meta-syntax))

(deftype non-symbol () '(not symbol))

(defun frob-flat-list (list &aux symbol atom atoms)
  (with-collector (results)
    (with-list-meta (%list list)     
      (match
       $[@(symbol symbol) !(setf atoms (make-collector))
         $[@(non-symbol atom) !(funcall atoms atom)]
         !(progn (results (list symbol (funcall atoms))) t)])
      (results))))

;TOY-PROBLEMS> (frob-flat-list '(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))

(eval-when (:compile-toplevel :load-toplevel :execute)
  (disable-meta-syntax))

Name: PHP FAGGOT 2009-12-12 20:01


function prog ($arr) {
    foreach ($arr as $e) if(preg_match("/^[a-z]+$/", $e)) $ret[$e] = array(); else { $ret[end(array_keys($ret))][] = $e; }
    return $ret;
    }

Name: Anonymous 2009-12-12 20:30

def foo(arr):
  def f(a, c, d):
    if c == len(a):
      return d
    else:
      if 97 <= ord(a[c]) <= 122:
        d.append([a[c],[]])
      else:
        d[-1][1].append(a[c])
      return f(a, c+1, d)
  return f(arr, 0, [])

a = ['a', '1', '2', '3', 'b', '4', '5', 'c', 'd', '8', '9', 'e']
print foo(a)

Name: Anonymous 2009-12-12 20:39

>>15
ONE WORD THE FORCED INDENTATION OF CODE THREAD OVER

Name: Lisp 2009-12-12 20:49


<?php
function toy_problem($input_array)
{
    preg_match_all('/([a-z])([0-9]+)?/i', implode($input_array), $tmp);
    return array_combine($tmp[1], $tmp[2]);
}
?>


Demo:


$test = array('a', 1, 2, 3, 'b', 4, 5, 'c', 'd', 8, 9, 'e');
print_r( toy_problem($test) );

Array
(
    [a] => 123
    [b] => 45
    [c] =>
    [d] => 89
    [e] =>
)

Name: 13 2009-12-12 20:54

Out of boredom, wrote one state-machine-based implementation, only using minimal CL:

(defun frob-flat-list (list) 
  (let ((element (pop list))
        symbol non-symbols result)   
    (tagbody      
     SYMBOL        
       (unless (symbolp element)
         (error "Not a symbol: ~A" element))
       (setf symbol element)
       ;;(go NON-SYMBOL)
     NON-SYMBOL
       (setf element (pop list))
       (cond
         ((symbolp element)            
          (push (list symbol (nreverse non-symbols)) result)
          (setf non-symbols nil)
          (go SYMBOL))
         (t           
          (push element non-symbols)         
          (go NON-SYMBOL))))
    (nreverse result)))

;TOY-PROBLEMS> (frob-flat-list '(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))

Name: Anonymous 2009-12-12 21:24

>>18
What? How does this tagbody thing work?

Name: Anonymous 2009-12-12 21:29

>>19
http://www.lispworks.com/documentation/HyperSpec/Body/s_tagbod.htm
Within the body of the TAGBODY block, you can establish labels, to which you can jump using GO. Basically, it's like goto, however it can also do non-local transfer of control: if you lexically capture a (go tag) within a closure, you can call that closure and jump within the tagbody (with some limits). This allows one to use TAGBODY to create new control structures, condition/error handling systems and other things. People don't usually use TAGBODY/GO within normal code, but mostly within macros, however since state machines fit its model very well, it's considered acceptable use too.

Name: Anonymous 2009-12-12 21:40

It's a trick! The problem is already solved!

If before solving the problem, the string looks like this:
"a123b45cd89e"
Then it would look exactly the same afterwards!

No work needs to be done!!

Name: Anonymous 2009-12-12 21:42

>>21
Why are you assuming input and output have to be strings? It's pretty obvious that OP is talking about a linked list of objects as input, and that the output is a linked list of linked lists of objects.

Name: Anonymous 2009-12-12 21:46


(define (hierarchize-list l)
 (define (nonsymbols m) (if (or (empty? m) (symbol? (car m))) '() (cons (car m) (nonsymbols (cdr m))))
 (define (next-symbol n) (if (or (empty? n) (symbol? (car n))) n (next-symbol (cdr n))))
 (if (empty? l) '() (cons (cons (car l) (nonsymbols (cdr l)) (hierarchize-list (next-symbol (cdr l))))))

Name: Anonymous 2009-12-12 21:47

>>22
How is this obvious? All I see are parentheses!

Furthermore, a linked list is an extremely inefficient way to store a series of characters; a null-terminated string is far superior. Remember, every byte is precious!!

Name: OP 2009-12-12 21:52

>>24
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:
... turning a list ... into a list of lists ...
Please consider reading the problem as well as looking at the example, it is usually enlightening. Efficiency wasn't the concern either, I was looking for clarity and conciseness. They are not mutually exclusive, I admit, but they are often at loggerheads.

Name: Lisp 2009-12-12 21:57

>>25
Sorry, I meant return array_combine($tmp[1], array_walk($tmp[2], 'str_split') );

Name: OP 2009-12-12 22:00

My own solution was

(define (mk-sym-list lst)
  (if (null? lst) '()
      (let-values (((vals rest) (break symbol? (cdr lst))))
        (cons (list (car lst) vals)
              (mk-sym-list rest)))))

and it takes break from SRFI 1.
I came across this problem when reading a few old posts on jao's blog[1],  but the problem [linked to in the post] was from a comp.lang.scheme thread [2]

--References--
1. http://programming-musings.org/2006/02/07/scheme-code-kata/
2. http://groups.google.com/group/comp.lang.scheme/browse_frm/thread/09a1d9ab8b5d9c5e/62efc2529696d172#62efc2529696d172

Name: PHP > Perl > Lisp 2009-12-12 22:01

>>26
Sorry, I meant array_map('str_split', $tmp[2])

Name: Anonymous 2009-12-12 22:04

>>27
I didn't use it in this solution, but does anyone else use a "let1" macro, for instances where they only wish to bind one value? I find the additional parentheses used to be a little redundant and distracting.

Name: Anonymous 2009-12-12 22:08

>>25

But a string can be any number of lists, depending on how pointers are used! It's all just bytes anyways!!

Anyways, FINE!!


#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
    int l = strlen(argv[1]);
    int p = 0;
    int i;
    for(i = 0; i < l; i++)
    {
        if(argv[1][i] >= 'a' && argv[1][i] <= 'z')
        {
            if(p)
            {
                printf(")) (%c (",argv[1][i]);
            }
            else
            {
                printf("(%c (",argv[1][i]);
                p = 1;
            }
        }
        else
        if(argv[1][i] == ')')
        {
            printf(")))");
        }
        else
        {
            printf("%c",argv[1][i]);
        }
    }
    printf("\n");
    return 0;
}


Which results in:


C:\Users\*\Desktop>gcc list.c -o list.exe

C:\Users\*\Desktop>list "(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-12 22:11

>>30
I believe you mean
But a string can be any number of lists, depending on how pointers are aused!
I have nothing against the text-based solutions, it just misses the point of the exercise.

Name: Anonymous 2009-12-12 22:13

>>31
God damn it, s/aused/abused/

Name: Anonymous 2009-12-12 22:14

>>31
But there is no point to the exercise! Strings are never stored as linked lists of characters in the ENTERPRISE!!

Name: Anonymous 2009-12-12 22:15

>>32
s/ab/an

Name: Anonymous 2009-12-12 22:26

>>33
It was never about strings, I merely suggested that you could use strings as a way of representing the symbols in a language that doesn't give you the flexibility to mix types in a list. As far as I know, very few languages actually have a symbol type (Lisp + derivatives, Erlang, Ruby), and Haskell and various other languages are strict about keeping list elements all of the same type.
No-one and I repeat NO-ONE is under the delusion that it is efficient to store strings as a list of characters.

Name: >>13 2009-12-12 22:30

>>33
Why do you think strings are stored as linked lists? That would be terribly inefficient.

Given OP's syntax, I'm mostly assuming Lisp/Scheme meaning of symbol/non-symbol, which would mean the following, in C-like languages:
symbol - an object/structure, usually referred by a pointer, the structure has a name as one of it's fields. If you want to simplify this, you're free to use null terminated strings
non-symbols - other types of objects, since it wasn't specified what it means. If you want to simplify this requirement, you could say they're numbers, even though that would probably be different from what OP asked.
a list - linked list: structure of 2 elements, first is a pointer to the object, the second is a pointer to the rest of the list. A symbol called NIL, or empty list object '() can be used to represent the empty list. If you want to simplify this in C, you could use a NULL or 0.

At least the meanings I assigned to the terms used in OP's problem, but maybe I'm reading too much into it.

Name: OP 2009-12-12 22:34

>>36
You are correct, although I was hoping that most of it was obvious from the context.Certainly a percentage of the /prog/ population provided solutions with no such coaxing. The strings were suggested as a way for the Haskeller (who has yet to post a solution ;) to participate while using his language of choice.

Name: Anonymous 2009-12-12 22:42

What is a ``symbol'' and why don't numbers qualify?

Name: Anonymous 2009-12-12 22:47

>>38
Just assume 2 disjointed types of objects, one is a symbol, the othes are not. It doesn't matter what the objects are, but if you want to simplify the problem, you could say one is a string, and the other is a number.

Name: Anonymous 2009-12-12 22:51

>>38
See if this make it any clearer to you http://www.psg.com/~dlamkins/sl/chapter03-05.html

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?

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