Author Topic: -={ Challenge }=- Nested Assoc++  (Read 6790 times)

0 Members and 1 Guest are viewing this topic.

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
-={ Challenge }=- Nested Assoc++
« on: May 23, 2011, 03:58:40 PM »
I think the Assoc++ function has been around for some time, something along the lines of:

Code: [Select]
([color=BLUE]defun[/color] _Assoc++ ( key alist )
  (
    ([color=BLUE]lambda[/color] ( pair )
      ([color=BLUE]if[/color] pair
        ([color=BLUE]subst[/color] ([color=BLUE]list[/color] key ([color=BLUE]1+[/color] ([color=BLUE]cadr[/color] pair))) pair alist)
        ([color=BLUE]cons[/color]  ([color=BLUE]list[/color] key 1) alist)
      )
    )
    ([color=BLUE]assoc[/color] key alist)
  )
)

Wherein, if a key is already present in the association list, its associated value would be incremented, else the new key would be added to the association list.

Such a function is really handy when counting the number of instances of multiple items, for example in this simple block counter:

Code: [Select]
([color=BLUE]defun[/color] c:test ( [color=BLUE]/[/color] ss i lst )
  ([color=BLUE]if[/color] ([color=BLUE]setq[/color] ss ([color=BLUE]ssget[/color] [color=MAROON]"_X"[/color] '((0 . [color=MAROON]"INSERT"[/color]))))
    ([color=BLUE]repeat[/color] ([color=BLUE]setq[/color] i ([color=BLUE]sslength[/color] ss))
      ([color=BLUE]setq[/color] lst (_Assoc++ ([color=BLUE]cdr[/color] ([color=BLUE]assoc[/color] 2 ([color=BLUE]entget[/color] ([color=BLUE]ssname[/color] ss ([color=BLUE]setq[/color] i ([color=BLUE]1-[/color] i)))))) lst))
    )
  )
  lst
)

But, say we have a situation in which items form a hierarchy, and you wish to count items based on two (or more) variable keys - at this point the Assoc++ function cannot be used since only one key can be queried.

For example:
Code: [Select]
_$ ([color=BLUE]setq[/color] alist (_nAssoc++ '([color=MAROON]"Item1"[/color] [color=MAROON]"SubItem1"[/color] [color=MAROON]"A"[/color]) alist))
(
    ([color=MAROON]"Item1"[/color]
        ([color=MAROON]"SubItem1"[/color]
            ([color=MAROON]"A"[/color] 1)
        )
    )
)

_$ ([color=BLUE]setq[/color] alist (_nAssoc++ '([color=MAROON]"Item1"[/color] [color=MAROON]"SubItem1"[/color] [color=MAROON]"B"[/color]) alist))
(
    ([color=MAROON]"Item1"[/color]
        ([color=MAROON]"SubItem1"[/color]
            ([color=MAROON]"B"[/color] 1)
            ([color=MAROON]"A"[/color] 1)
        )
    )
)

_$ ([color=BLUE]setq[/color] alist (_nAssoc++ '([color=MAROON]"Item1"[/color] [color=MAROON]"SubItem2"[/color] [color=MAROON]"A"[/color]) alist))
(
    ([color=MAROON]"Item1"[/color]
        ([color=MAROON]"SubItem2"[/color]
            ([color=MAROON]"A"[/color] 1)
        )
        ([color=MAROON]"SubItem1"[/color]
            ([color=MAROON]"B"[/color] 1)
            ([color=MAROON]"A"[/color] 1)
        )
    )
)

_$ ([color=BLUE]setq[/color] alist (_nAssoc++ '([color=MAROON]"Item2"[/color] [color=MAROON]"SubItem1"[/color] [color=MAROON]"A"[/color]) alist))
(
    ([color=MAROON]"Item2"[/color]
        ([color=MAROON]"SubItem1"[/color]
            ([color=MAROON]"A"[/color] 1)
        )
    )
    ([color=MAROON]"Item1"[/color]
        ([color=MAROON]"SubItem2"[/color]
            ([color=MAROON]"A"[/color] 1)
        )
        ([color=MAROON]"SubItem1"[/color]
            ([color=MAROON]"B"[/color] 1)
            ([color=MAROON]"A"[/color] 1)
        )
    )
)

_$ ([color=BLUE]setq[/color] alist (_nAssoc++ '([color=MAROON]"Item1"[/color] [color=MAROON]"SubItem1"[/color] [color=MAROON]"A"[/color]) alist))
(
    ([color=MAROON]"Item2"[/color]
        ([color=MAROON]"SubItem1"[/color]
            ([color=MAROON]"A"[/color] 1)
        )
    )
    ([color=MAROON]"Item1"[/color]
        ([color=MAROON]"SubItem2"[/color]
            ([color=MAROON]"A"[/color] 1)
        )
        ([color=MAROON]"SubItem1"[/color]
            ([color=MAROON]"B"[/color] 1)
            ([color=MAROON]"A"[/color] 2)
        )
    )
)

This was my solution,

Code: [Select]
[color=green];; Scroll for solution  -  so as not to spoil the challenge ;)[/color]




























([color=BLUE]defun[/color] _nAssoc++ ( keys alist )
  (
    ([color=BLUE]lambda[/color] ( pair )
      ([color=BLUE]if[/color] pair
        ([color=BLUE]subst[/color]
          ([color=BLUE]cons[/color] ([color=BLUE]car[/color] keys)
            ([color=BLUE]if[/color] ([color=BLUE]cdr[/color] keys)
              (_nAssoc++ ([color=BLUE]cdr[/color] keys) ([color=BLUE]cdr[/color] pair))
              ([color=BLUE]list[/color] ([color=BLUE]1+[/color] ([color=BLUE]cadr[/color] pair)))
            )
          )
          pair
          alist
        )
        ([color=BLUE]cons[/color]
          ([color=BLUE]if[/color] ([color=BLUE]cdr[/color] keys)
            ([color=BLUE]cons[/color] ([color=BLUE]car[/color] keys) (_nAssoc++ ([color=BLUE]cdr[/color] keys) [color=BLUE]nil[/color]))
            ([color=BLUE]list[/color] ([color=BLUE]car[/color] keys) 1)
          )
          alist
        )
      )
    )
    ([color=BLUE]assoc[/color] ([color=BLUE]car[/color] keys) alist)
  )
)

Have fun!

ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: -={ Challenge }=- Nested Assoc++
« Reply #1 on: May 23, 2011, 04:24:16 PM »
Can I show my version or better to wait a week?

ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: -={ Challenge }=- Nested Assoc++
« Reply #2 on: May 23, 2011, 04:27:38 PM »
My results are slightly different, but I like it! :)

Code: [Select]
(setq k '("Item1" "SubItem1" "A") l nil)
(setq l (f k l))
(("Item1" ("SubItem1" ("A" 1))));ElpanovEvgeniy
(("Item1" ("SubItem1" ("A" 1))))

(setq l (f '("Item1" "SubItem1" "B") l))
(("Item1" ("SubItem1" ("A" 1) ("B" 1))));ElpanovEvgeniy
(("Item1" ("SubItem1" ("B" 1) ("A" 1))))

(setq l (f '("Item1" "SubItem2" "A") l))
(("Item1" ("SubItem1" ("A" 1) ("B" 1)) ("SubItem2" ("A" 1))));ElpanovEvgeniy
(("Item1" ("SubItem2" ("A" 1)) ("SubItem1" ("B" 1) ("A" 1))))

(setq l (f '("Item2" "SubItem1" "A") l))
(("Item1" ("SubItem1" ("A" 1) ("B" 1)) ("SubItem2" ("A" 1))) ("Item2" ("SubItem1" ("A" 1))));ElpanovEvgeniy
(("Item2" ("SubItem1" ("A" 1))) ("Item1" ("SubItem2" ("A" 1)) ("SubItem1" ("B" 1) ("A" 1))))

(setq l (f '("Item1" "SubItem1" "A") l))
(("Item1" ("SubItem1" ("A" 2) ("B" 1)) ("SubItem2" ("A" 1))) ("Item2" ("SubItem1" ("A" 1))));ElpanovEvgeniy
(("Item2" ("SubItem1" ("A" 1))) ("Item1" ("SubItem2" ("A" 1)) ("SubItem1" ("B" 1) ("A" 2))))
« Last Edit: May 23, 2011, 04:35:32 PM by ElpanovEvgeniy »

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: -={ Challenge }=- Nested Assoc++
« Reply #3 on: May 23, 2011, 04:32:38 PM »
Can I show my version or better to wait a week?

I'll bet your solution has half the lines of code that mine has  :evil:

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: -={ Challenge }=- Nested Assoc++
« Reply #4 on: May 23, 2011, 04:35:57 PM »
My results are slightly different, but I like it! :)

Ah yes! Looks like I need a reverse in there:

Code: [Select]
(defun _nAssoc++ ( keys alist )
  (
    (lambda ( pair )
      (if pair
        (subst
          (cons (car keys)
            (if (cdr keys)
              (_nAssoc++ (cdr keys) (cdr pair))
              (list (1+ (cadr pair)))
            )
          )
          pair
          alist
        )
[color=blue]        (reverse[/color]
          (cons
            (if (cdr keys)
              (cons (car keys) (_nAssoc++ (cdr keys) nil))
              (list (car keys) 1)
            )
            alist
          )
[color=blue]        )[/color]
      )
    )
    (assoc (car keys) alist)
  )
)

ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: -={ Challenge }=- Nested Assoc++
« Reply #5 on: May 23, 2011, 04:45:35 PM »
I'll bet your solution has half the lines of code that mine has  :evil:

I wrote 8 lines, but some of them have a greater length  :-)

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: -={ Challenge }=- Nested Assoc++
« Reply #6 on: May 23, 2011, 05:55:55 PM »
I'll bet your solution has half the lines of code that mine has  :evil:

I wrote 8 lines, but some of them have a greater length  :-)

We could all play that game  :evil:

Code: [Select]
(defun f ( k l / a )
  (if (setq a (assoc (car k) l))
    (subst (cons (car k) (if (cdr k) (f (cdr k) (cdr a)) (list (1+ (cadr a))))) a l)
    (reverse (cons (if (cdr k) (cons (car k) (f (cdr k) nil)) (list (car k) 1)) l))
  )
)
« Last Edit: May 23, 2011, 06:20:12 PM by Lee Mac »

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: -={ Challenge }=- Nested Assoc++
« Reply #7 on: May 23, 2011, 06:26:54 PM »
Another, cross-recursive example:

Code: [Select]
(defun f ( k l ) (if k (g k l) (list (1+ (car l)))))

(defun g ( k l / a )
  (if k
    (if (setq a (assoc (car k) l))
      (subst (cons (car k) (f (cdr k) (cdr a))) a l)
      (cons  (cons (car k) (g (cdr k) nil)) l)
    )
   '(1)
  )
)

Code: [Select]
_$ (setq l (f '("Item1" "SubItem1" "A") l))
(("Item1" ("SubItem1" ("A" 1))))
_$ (setq l (f '("Item1" "SubItem1" "B") l))
(("Item1" ("SubItem1" ("B" 1) ("A" 1))))

[Didn't want to spoil it with the reverse...] :P

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: -={ Challenge }=- Nested Assoc++
« Reply #8 on: May 23, 2011, 06:27:54 PM »
Or, to remove the cross-recursive call...

Code: [Select]
(defun g ( k l / a )
  (if k
    (if (setq a (assoc (car k) l))
      (subst (cons (car k) (g (cdr k) (cdr a))) a l)
      (cons  (cons (car k) (g (cdr k) nil)) l)
    )
    (if l (list (1+ (car l))) '(1))
  )
)

VovKa

  • Water Moccasin
  • Posts: 1632
  • Ukraine
Re: -={ Challenge }=- Nested Assoc++
« Reply #9 on: May 24, 2011, 03:18:05 AM »
it looks like you are challenging yourself, Lee :)

ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: -={ Challenge }=- Nested Assoc++
« Reply #10 on: May 24, 2011, 04:44:43 AM »
my version
Code: [Select]
(defun f (k l)
 (cond
  ((and l (not k)) (list (1+ (car l))))
  ((not k) '(1))
  ((or (not l) (= (car k) (caar l))) (cons (cons (car k) (f (cdr k) (cdar l))) (cdr l)))
  ((cons (car l) (f k (cdr l))))
 )
)

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: -={ Challenge }=- Nested Assoc++
« Reply #11 on: May 24, 2011, 07:08:29 AM »
it looks like you are challenging yourself, Lee :)

I tend to constantly think my code is not good enough and challenge myself to produce something better...  I'm enjoying this challenge though :-)

my version
Code: [Select]
(defun f (k l)
 (cond
  ((and l (not k)) (list (1+ (car l))))
  ((not k) '(1))
  ((or (not l) (= (car k) (caar l))) (cons (cons (car k) (f (cdr k) (cdar l))) (cdr l)))
  ((cons (car l) (f k (cdr l))))
 )
)

Nice idea Evgeniy! It looks like we followed a similar route to increment the value, but you chose not to use assoc, but rather iterate through the list...  :-)

Andrea

  • Water Moccasin
  • Posts: 2372
Re: -={ Challenge }=- Nested Assoc++
« Reply #12 on: May 24, 2011, 11:09:48 AM »
How nice it is to see How 2 of best programmer can play together...very enjoying.
good job guys.

 :-)
Keep smile...

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: -={ Challenge }=- Nested Assoc++
« Reply #13 on: May 24, 2011, 03:12:21 PM »
How nice it is to see How 2 of best programmer can play together...very enjoying.
good job guys.

 :-)

Thanks Andrea :-)

Although Evgeniy is much cleverer than I  :angel:

highflyingbird

  • Bull Frog
  • Posts: 415
  • Later equals never.
Re: -={ Challenge }=- Nested Assoc++
« Reply #14 on: May 26, 2011, 08:20:08 AM »
How nice it is to see How 2 of best programmer can play together...very enjoying.
good job guys.

 :-)

Thanks Andrea :-)

Although Evgeniy is much cleverer than I  :angel:
A Chinese idiom:英雄惜英雄。 :laugh:
I am a bilingualist,Chinese and Chinglish.