From: mahatGma
Subject: Bundling elements of a list
Date: 
Message-ID: <a74238e3-e889-47f3-87af-38144da73155@62g2000hsn.googlegroups.com>
I try to bundle elements of a list serially as sums of a specific
quantity.
For instance as sums of 1: '( (.75 .25) (.50 .25 .25) (.25 .25 .25 .
25))
Can anybody help me?

From: William D Clinger
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <39688902-2ca3-4570-a6fe-011b5bd979ca@34g2000hsz.googlegroups.com>
mahatGma wrote:
> I try to bundle elements of a list serially as sums of a specific
> quantity.
> For instance as sums of 1: '( (.75 .25) (.50 .25 .25) (.25 .25 .25 .25))
> Can anybody help me?

You haven't done a very good job of explaining what
you're trying to accomplish, but you might start by
using exact instead of inexact numbers:

    '( (3/4 1/4) (1/2 1/4 1/4) (1/4 1/4 1/4 1/4))

Remember:  Only you can prevent roundoff errors.

Will
From: Pascal Bourguignon
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <87tzk0d5jq.fsf@thalassa.informatimago.com>
mahatGma <········@gmail.com> writes:

> I try to bundle elements of a list serially as sums of a specific
> quantity.
> For instance as sums of 1: '( (.75 .25) (.50 .25 .25) (.25 .25 .25 .
> 25))
> Can anybody help me?

It doesn't look like you're thinking too much...

(defun find-compositions (op- op< op0 target tokens)
  (cond
    ((endp tokens)
     '())
    ((or (funcall op< (funcall op- target (first tokens)) op0))
     (find-compositions op- op< op0 target (rest tokens)))
    ((funcall op< op0 (funcall op- target (first tokens)))
     (append (mapcar (lambda (subcomposition) (cons (first tokens) subcomposition))
                     (find-compositions op- op< op0 (funcall op- target (first tokens))
                                        (rest tokens)))
             (find-compositions op- op< op0 target (rest tokens))))
    (t
     (append (list (list (first tokens)))
             (find-compositions op- op< op0 target (rest tokens))))))

(find-compositions (function -) (function <) 0 
  100/100 '(75/100 25/100 25/100 50/100 25/100 25/100))
--> ((3/4 1/4) (3/4 1/4) (3/4 1/4) (3/4 1/4) (1/4 1/4 1/2) (1/4 1/4 1/4 1/4) (1/4 1/2 1/4)
     (1/4 1/2 1/4) (1/4 1/2 1/4) (1/4 1/2 1/4) (1/2 1/4 1/4))

If you don't want duplicates:

(remove-duplicates (find-compositions (function -) (function <) 0 
                         100/100 '(75/100 25/100 25/100 50/100 25/100 25/100))
                   :test (lambda (a b) (and (subsetp a b :test (function =))
                                       (subsetp b a :test (function =)))))
--> ((3/4 1/4) (1/4 1/4 1/4 1/4) (1/2 1/4 1/4))

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

This is a signature virus.  Add me to your signature and help me to live.
From: William James
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <e0b746ea-a655-41f5-8c84-9938d6af310a@k2g2000hse.googlegroups.com>
On Feb 22, 3:50 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> mahatGma <········@gmail.com> writes:
> > I try to bundle elements of a list serially as sums of a specific
> > quantity.
> > For instance as sums of 1: '( (.75 .25) (.50 .25 .25) (.25 .25 .25 .
> > 25))
> > Can anybody help me?
>
> It doesn't look like you're thinking too much...
>
> (defun find-compositions (op- op< op0 target tokens)
>   (cond
>     ((endp tokens)
>      '())
>     ((or (funcall op< (funcall op- target (first tokens)) op0))
>      (find-compositions op- op< op0 target (rest tokens)))
>     ((funcall op< op0 (funcall op- target (first tokens)))
>      (append (mapcar (lambda (subcomposition) (cons (first tokens) subcomposition))
>                      (find-compositions op- op< op0 (funcall op- target (first tokens))
>                                         (rest tokens)))
>              (find-compositions op- op< op0 target (rest tokens))))
>     (t
>      (append (list (list (first tokens)))
>              (find-compositions op- op< op0 target (rest tokens))))))
>
> (find-compositions (function -) (function <) 0
>   100/100 '(75/100 25/100 25/100 50/100 25/100 25/100))
> --> ((3/4 1/4) (3/4 1/4) (3/4 1/4) (3/4 1/4) (1/4 1/4 1/2) (1/4 1/4 1/4 1/4) (1/4 1/2 1/4)
>      (1/4 1/2 1/4) (1/4 1/2 1/4) (1/4 1/2 1/4) (1/2 1/4 1/4))

A Ruby way:

class Array
  def group_till &block
    a = [[]]
    self.each{|x|
      a << []  if block[ a[-1] ]
      a[-1] << x }
    a
  end
end

p [0.75,0.25,0.50,0.25,0.25,0.25,0.25,0.25,0.25].
  group_till{|a| a.inject(0){|s,x| s+x} >= 1.0 }

--> [[0.75, 0.25], [0.5, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]]

>
> If you don't want duplicates:

Use .uniq.

>
> (remove-duplicates (find-compositions (function -) (function <) 0
>                          100/100 '(75/100 25/100 25/100 50/100 25/100 25/100))
>                    :test (lambda (a b) (and (subsetp a b :test (function =))
>                                        (subsetp b a :test (function =)))))
> --> ((3/4 1/4) (1/4 1/4 1/4 1/4) (1/2 1/4 1/4))
From: Pascal Bourguignon
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <87myprdgmm.fsf@thalassa.informatimago.com>
William James <·········@yahoo.com> writes:

> On Feb 22, 3:50 pm, Pascal Bourguignon <····@informatimago.com> wrote:
>> mahatGma <········@gmail.com> writes:
>> > I try to bundle elements of a list serially as sums of a specific
>> > quantity.
>> > For instance as sums of 1: '( (.75 .25) (.50 .25 .25) (.25 .25 .25 .
>> > 25))
>> > Can anybody help me?
>>
>> It doesn't look like you're thinking too much...
>>
>> (defun find-compositions (op- op< op0 target tokens)
>>   (cond
>>     ((endp tokens)
>>      '())
>>     ((or (funcall op< (funcall op- target (first tokens)) op0))
>>      (find-compositions op- op< op0 target (rest tokens)))
>>     ((funcall op< op0 (funcall op- target (first tokens)))
>>      (append (mapcar (lambda (subcomposition) (cons (first tokens) subcomposition))
>>                      (find-compositions op- op< op0 (funcall op- target (first tokens))
>>                                         (rest tokens)))
>>              (find-compositions op- op< op0 target (rest tokens))))
>>     (t
>>      (append (list (list (first tokens)))
>>              (find-compositions op- op< op0 target (rest tokens))))))
>>
>> (find-compositions (function -) (function <) 0
>>   100/100 '(75/100 25/100 25/100 50/100 25/100 25/100))
>> --> ((3/4 1/4) (3/4 1/4) (3/4 1/4) (3/4 1/4) (1/4 1/4 1/2) (1/4 1/4 1/4 1/4) (1/4 1/2 1/4)
>>      (1/4 1/2 1/4) (1/4 1/2 1/4) (1/4 1/2 1/4) (1/2 1/4 1/4))
>
> A Ruby way:
>
> class Array
>   def group_till &block
>     a = [[]]
>     self.each{|x|
>       a << []  if block[ a[-1] ]
>       a[-1] << x }
>     a
>   end
> end
>
> p [0.75,0.25,0.50,0.25,0.25,0.25,0.25,0.25,0.25].
>   group_till{|a| a.inject(0){|s,x| s+x} >= 1.0 }
>
> --> [[0.75, 0.25], [0.5, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]]


Now try:

(defun explode (symbol)
  ;; too bad we lost this function between LISP 1.5 and CL... ;-)
  (map 'list (lambda (ch) (intern (string ch))) (string symbol)))

(defun strict-subsetp (a b)
  (and (subsetp a b) (not (subsetp b a))))

(find-compositions (function set-difference)
                   (function strict-subsetp)
                   '()
                   '(a e i o u y) 
                   (mapcar (function explode)
                           '(you cannot really appreciate dilbert 
                             unless you read it in the original
                             klingon)))

-->
(((Y O U) (C A N N O ...) (R E A L L ...) (A P P R E ...))
 ((Y O U) (C A N N O ...) (R E A L L ...) (D I L B E ...))
 ((Y O U) (C A N N O ...) (R E A L L ...) (U N L E S ...) (Y O U) ...)
 ((Y O U) (C A N N O ...) (R E A L L ...) (U N L E S ...) (Y O U) ...)
 ((Y O U) (C A N N O ...) (R E A L L ...) (U N L E S ...) (Y O U) ...) ...)


>> If you don't want duplicates:
>>
>> (remove-duplicates (find-compositions (function -) (function <) 0
>>                          100/100 '(75/100 25/100 25/100 50/100 25/100 25/100))
>>                    :test (lambda (a b) (and (subsetp a b :test (function =))
>>                                        (subsetp b a :test (function =)))))
>
> Use .uniq.

.uniq doesn't take an equal predicate as argument, so you just cannot
use it.

(remove-duplicates
 (find-compositions (function set-difference)
                    (function strict-subsetp)
                    '()
                    '(a e i o u y) 
                    (mapcar (function explode)
                            '(you cannot really appreciate dilbert 
                              unless you read it in the original
                              klingon)))
 :test (lambda (a b)
         (and (subsetp a b :test (function equal))
              (subsetp b a :test (function equal)))))
-->
(((C A N N O ...) (R E A L L ...) (A P P R E ...) (D I L B E ...)
  (U N L E S ...))
 ((C A N N O ...) (R E A L L ...) (A P P R E ...) (D I L B E ...) (Y O U))
 ((C A N N O ...) (R E A L L ...) (A P P R E ...) (U N L E S ...))
 ((C A N N O ...) (R E A L L ...) (A P P R E ...) (Y O U))
 ((C A N N O ...) (R E A L L ...) (D I L B E ...) (U N L E S ...)) ...)




<humour>Please don't polute this professionnal programming language
newsgroup with your toy language.  We've got serrious stuff to do
here.</humour>


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"You cannot really appreciate Dilbert unless you read it in the
original Klingon"
 
From: William James
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <eaf8d6d6-4299-496b-bb3b-cd6b8a81596b@s37g2000prg.googlegroups.com>
On Feb 23, 6:03 am, Pascal Bourguignon <····@informatimago.com> wrote:
> William James <·········@yahoo.com> writes:

> > Use .uniq.
>
> .uniq doesn't take an equal predicate as argument, so you just cannot
> use it.

Ruby's Array#uniq:

%w(truth is no defense)
    ==>["truth", "is", "no", "defense"]
%w(truth is no defense).map{|s| s.split("").map{|c| c.to_sym}}
    ==>[[:t, :r, :u, :t, :h], [:i, :s], [:n, :o],
 [:d, :e, :f, :e, :n, :s, :e]]
%w(truth is no defense).map{|s| s.split("").map{|c| c.to_sym}}.
flatten
    ==>[:t, :r, :u, :t, :h, :i, :s, :n, :o, :d, :e, :f, :e,
 :n, :s, :e]
%w(truth is no defense).map{|s| s.split("").map{|c|
  c.to_sym}}.flatten.uniq
    ==>[:t, :r, :u, :h, :i, :s, :n, :o, :d, :e, :f]

>
> (remove-duplicates
>  (find-compositions (function set-difference)
>                     (function strict-subsetp)
>                     '()
>                     '(a e i o u y)
>                     (mapcar (function explode)
>                             '(you cannot really appreciate dilbert
>                               unless you read it in the original
>                               klingon)))
>  :test (lambda (a b)
>          (and (subsetp a b :test (function equal))
>               (subsetp b a :test (function equal)))))
> -->
> (((C A N N O ...) (R E A L L ...) (A P P R E ...) (D I L B E ...)
>   (U N L E S ...))
>  ((C A N N O ...) (R E A L L ...) (A P P R E ...) (D I L B E ...) (Y O U))
>  ((C A N N O ...) (R E A L L ...) (A P P R E ...) (U N L E S ...))
>  ((C A N N O ...) (R E A L L ...) (A P P R E ...) (Y O U))
>  ((C A N N O ...) (R E A L L ...) (D I L B E ...) (U N L E S ...)) ...)
>
> <humour>Please don't polute this professionnal programming language
> newsgroup with your toy language.  We've got serrious stuff to do
> here.</humour>

I am not unmoved by your cry for mercy.  And you're right: it
really isn't fair for a man armed with a samurai sword to
engage in combat with one who has only a flint knife.
From: Pascal J. Bourguignon
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <7cmyppfis0.fsf@pbourguignon.anevia.com>
William James <·········@yahoo.com> writes:

> On Feb 23, 6:03 am, Pascal Bourguignon <····@informatimago.com> wrote:
>> William James <·········@yahoo.com> writes:
>
>> > Use .uniq.
>>
>> .uniq doesn't take an equal predicate as argument, so you just cannot
>> use it.
>
> Ruby's Array#uniq:
>
> %w(truth is no defense)
>     ==>["truth", "is", "no", "defense"]
> %w(truth is no defense).map{|s| s.split("").map{|c| c.to_sym}}
>     ==>[[:t, :r, :u, :t, :h], [:i, :s], [:n, :o],
>  [:d, :e, :f, :e, :n, :s, :e]]
> %w(truth is no defense).map{|s| s.split("").map{|c| c.to_sym}}.
> flatten
>     ==>[:t, :r, :u, :t, :h, :i, :s, :n, :o, :d, :e, :f, :e,
>  :n, :s, :e]
> %w(truth is no defense).map{|s| s.split("").map{|c|
>   c.to_sym}}.flatten.uniq
>     ==>[:t, :r, :u, :h, :i, :s, :n, :o, :d, :e, :f]
>
>>
>> (remove-duplicates
>>  (find-compositions (function set-difference)
>>                     (function strict-subsetp)
>>                     '()
>>                     '(a e i o u y)
>>                     (mapcar (function explode)
>>                             '(you cannot really appreciate dilbert
>>                               unless you read it in the original
>>                               klingon)))
>>  :test (lambda (a b)
>>          (and (subsetp a b :test (function equal))
>>               (subsetp b a :test (function equal)))))
>> -->
>> (((C A N N O ...) (R E A L L ...) (A P P R E ...) (D I L B E ...)
>>   (U N L E S ...))
>>  ((C A N N O ...) (R E A L L ...) (A P P R E ...) (D I L B E ...) (Y O U))
>>  ((C A N N O ...) (R E A L L ...) (A P P R E ...) (U N L E S ...))
>>  ((C A N N O ...) (R E A L L ...) (A P P R E ...) (Y O U))
>>  ((C A N N O ...) (R E A L L ...) (D I L B E ...) (U N L E S ...)) ...)

Here, I use REMOVE-DUPLICATES to remove duplicate sets.  To do that, I
give it a :test parameter which is a set-equal function defined as an
anonymous function that consider sets of elements that have as
equivalence relationship EQUAL.

We know (or assume) that Ruby's Array#uniq is generic (it will use the
equal method of the objects in the array).  But if you want to use it
on a different equal function, you cannot.  Therefore, the 'unique'
algorithm implemented by uniq cannot be reused in all situations,
while that algorithm implemented by remove-duplicates can.  More code
reuse with 'functional' languages than 'OO' languages ;-)


>> <humour>Please don't polute this professionnal programming language
>> newsgroup with your toy language.  We've got serrious stuff to do
>> here.</humour>
>
> I am not unmoved by your cry for mercy.  And you're right: it
> really isn't fair for a man armed with a samurai sword to
> engage in combat with one who has only a flint knife.

-- 
__Pascal Bourguignon__
From: William James
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <635b48cc-cfdb-4a5d-a2f7-22aaa2200c80@q78g2000hsh.googlegroups.com>
On Feb 25, 4:10 am, ····@informatimago.com (Pascal J. Bourguignon)
wrote:

>
> Here, I use REMOVE-DUPLICATES to remove duplicate sets.  To do that, I
> give it a :test parameter which is a set-equal function defined as an
> anonymous function that consider sets of elements that have as
> equivalence relationship EQUAL.
>
> We know (or assume) that Ruby's Array#uniq is generic (it will use the
> equal method of the objects in the array).  But if you want to use it
> on a different equal function, you cannot.  Therefore, the 'unique'
> algorithm implemented by uniq cannot be reused in all situations,
> while that algorithm implemented by remove-duplicates can.  More code
> reuse with 'functional' languages than 'OO' languages ;-)

Let's define an Array method that accepts an anonymous function.
If this function returns the same result for two elements of the
array, we have a duplicate.

class Array
  def unique
    inject([]){|a,x|
      a.any?{|n| yield(n)==yield(x)} ? a : a << x }
  end
end

In the example below, if m and n are two elements of the array,
one is a duplicate if (m mod 5) = (n mod 5).

p [3,4,5,9,10,12,13,15].unique{|x| x % 5 }

 ---> [3, 4, 5, 12]

--
Use this [sword] for me, if I rule well; if not, against me.
  --- Trajan
From: William James
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <b19e81c8-8dc9-43dd-8d1a-b2ec4024c19c@p73g2000hsd.googlegroups.com>
On Feb 26, 12:22 pm, William James <·········@yahoo.com> wrote:
> On Feb 25, 4:10 am, ····@informatimago.com (Pascal J. Bourguignon)
> wrote:
>
>
>
> > Here, I use REMOVE-DUPLICATES to remove duplicate sets.  To do that, I
> > give it a :test parameter which is a set-equal function defined as an
> > anonymous function that consider sets of elements that have as
> > equivalence relationship EQUAL.
>
> > We know (or assume) that Ruby's Array#uniq is generic (it will use the
> > equal method of the objects in the array).  But if you want to use it
> > on a different equal function, you cannot.  Therefore, the 'unique'
> > algorithm implemented by uniq cannot be reused in all situations,
> > while that algorithm implemented by remove-duplicates can.  More code
> > reuse with 'functional' languages than 'OO' languages ;-)
>
> Let's define an Array method that accepts an anonymous function.
> If this function returns the same result for two elements of the
> array, we have a duplicate.
>
> class Array
>   def unique
>     inject([]){|a,x|
>       a.any?{|n| yield(n)==yield(x)} ? a : a << x }
>   end
> end
>
> In the example below, if m and n are two elements of the array,
> one is a duplicate if (m mod 5) = (n mod 5).
>
> p [3,4,5,9,10,12,13,15].unique{|x| x % 5 }
>
>  ---> [3, 4, 5, 12]
>
> --
> Use this [sword] for me, if I rule well; if not, against me.
>   --- Trajan

This much faster version is from the Ruby newsgroup.

module Enumerable
  def uniq_by
    h = {}; inject([]) {|a,x| h[yield(x)] ||= a << x}
  end
end
From: William James
Subject: Re: Bundling elements of a list
Date: 
Message-ID: <797e2bdb-1da1-42fb-9a65-1745e2726c17@59g2000hsb.googlegroups.com>
On Feb 22, 3:09 pm, mahatGma <········@gmail.com> wrote:
> I try to bundle elements of a list serially as sums of a specific
> quantity.
> For instance as sums of 1: '( (.75 .25) (.50 .25 .25) (.25 .25 .25 .
> 25))
> Can anybody help me?

Arc

(def group-till (fun lst)
  (let accum '(())
    (each item lst
      (if (fun car.accum)  (push '() accum))
      (++ car.accum list.item))
    rev.accum))

(prn
(group-till [ >= (apply + _) 1.0 ]
  '(0.75 0.25 0.50 0.25 0.25 0.25 0.25 0.25 0.25))
)

 --->((0.75 0.25) (0.5 0.25 0.25) (0.25 0.25 0.25 0.25))