(foo '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 )0.05)
;0.05 is fuzz
-->((1.19 1.2 1.21 1.22 1.23 1.25))
;;;1.25-1.19=0.6 > 0.5!
**********************************************************************************_$ (List:DuplicatesEq '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.3 ) 0.05)
(1.19 1.2 1.21 1.22 1.23)
Nice solution Irneb :-)Thanks. Though yours is a lot more optimal (especially for long lists with lots of duplication).
(listdupesfuzz '(1.00 1.03 1.06) 0.05)
(List:DuplicatesEq '(1.00 1.03 1.06) 0.05)
who is right? :police:Code: [Select](listdupesfuzz '(1.00 1.03 1.06) 0.05)
(List:DuplicatesEq '(1.00 1.03 1.06) 0.05)
But this requires that the list is sorted before processing otherwise the grouping will be ambiguous...Well if the list is sorted (if such assumption can be made) then the algorithm could be optimized a lot more - seeing as the search for duplicates only need to continue past current until a new non-duplicate is found.
((1.00 1.03) (1.06 1.09) (2.06 2.09))
But then 1.03 should also group together with 1.06 (e.g.) shouldn't it? Not to mention shouldn't 2.09 and 3.02 also be grouped? But then a duplicate is repeated in the result.; Option 1
((1.00 1.03) (1.03 1.06) (1.06 1.09) (2.06 2.09) (2.09 3.02))
; Option 2
((1.00 1.03 1.06 1.09) (2.06 2.09 3.02))
And as per the OP it seems option 2 is what's supposed to happen.(UNIQUE_PAIRS '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.3 )0.05)If the comment is to be believed then it's not as I thought. Since in such case 1.23 and 1.3 should also be considered duplicates, shouldn't they? Not to mention 1.0 and 1.1 (if 0.1 fuzz is considered inclusive).
;0.1 is fuzz
-->((1.19 1.2 1.21 1.22 1.23))
[/code]
(setq l '(1.00 1.03 1.06 1.09 1.12 1.15 1.18 1.21 1.24) a 0.05)
(mapcar '(lambda (c) (vl-remove-if-not '(lambda (b) (equal b c a)) l)) l)
=>> ((1.0 1.03) (1.0 1.03 1.06) (1.03 1.06 1.09) (1.06 1.09 1.12) (1.09 1.12 1.15) (1.12 1.15 1.18) (1.15 1.18 1.21) (1.18 1.21 1.24) (1.21 1.24))
(setq l '(1.00 1.03 1.06 1.09 1.12 1.15 1.18 1.21 1.24) a 0.05)
(defun f (l a)
(if l
(cons (vl-remove-if-not '(lambda (b) (equal (car l) b a)) l)
(f (vl-remove-if '(lambda (b) (equal (car l) b a)) l) a)
)
)
)
(f l a)
=>> ((1.0 1.03) (1.06 1.09) (1.12 1.15) (1.18 1.21) (1.24))
@xiaxiang, how should the output be structured?Sorry for late. I think the original list should be "re" grouped and output as nested list.Code - Auto/Visual Lisp: [Select]
_$ (listdupesfuzz '(1.0 1.1 1.19 5.0 5.01 4.98 1.2 1.21 1.22 1.23 1.3) 0.05) ((1.19 1.2 1.21 1.22 1.23) (5.0 5.01 4.98)) (1.19 5.0 5.01 4.98 1.2 1.21 1.22 1.23)
((1.19 1.2 1.21 1.22 1.23) (5.0 5.01 4.98))
This result is right.
Though there's another ambiguous situation:I must applogize for that the comment for those codes is wrong. The fuzz is 0.05.
Quote from: xiaxiang on Today at 04:56:07 amCode: [Select](UNIQUE_PAIRS '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.3 )0.05)
If the comment is to be believed then it's not as I thought. Since in such case 1.23 and 1.3 should also be considered duplicates, shouldn't they? Not to mention 1.0 and 1.1 (if 0.1 fuzz is considered inclusive).
;0.1 is fuzz
-->((1.19 1.2 1.21 1.22 1.23))
Well if the list is sorted (if such assumption can be made) then the algorithm could be optimized a lot more - seeing as the search for duplicates only need to continue past current until a new non-duplicate is found.Yes the list is sorted.
IMO there's 2 alternative approaches to this:The Option 2 is the result what I required.
Code: [Select]
; Option 1
((1.00 1.03) (1.03 1.06) (1.06 1.09) (2.06 2.09) (2.09 3.02))
; Option 2
((1.00 1.03 1.06 1.09) (2.06 2.09 3.02))
And as per the OP it seems option 2 is what's supposed to happen.
;;Lee mac
命令: (listdupesfuzz '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 ) 0.05)
((1.19 1.2 1.21 1.22 1.23))
;;Irneb
命令: (LIST:DUPLICATESEQ '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 ) 0.05)
(1.19 1.2 1.21 1.22 1.23 1.25)
(defun listdupesfuzz ( lst fuz / itm tmp )
(if (setq itm (car lst))
(progn
(setq lst
(vl-remove-if '(lambda ( x )
(if (equal x itm fuz)
(setq tmp (cons x tmp))
)
) (cdr lst)
)
)
(if tmp
(cons (cons itm (reverse tmp)) (listdupesfuzz lst fuz))
(listdupesfuzz lst fuz)
)
)
)
)
命令: (LM:UniqueFuzz '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 ) 0.05)
(1.0 1.1 1.19 1.25 1.3)
So the judgment which was from the first item to the end of the list is not suit for my condition.OK, here's an iterative + imperative attempt by first sorting the list:@xiaxiang, how should the output be structured?Sorry for late. I think the original list should be "re" grouped and output as nested list.Code - Auto/Visual Lisp: [Select]
_$ (listdupesfuzz '(1.0 1.1 1.19 5.0 5.01 4.98 1.2 1.21 1.22 1.23 1.3) 0.05) ((1.19 1.2 1.21 1.22 1.23) (5.0 5.01 4.98)) (1.19 5.0 5.01 4.98 1.2 1.21 1.22 1.23)
SoCode: [Select]((1.19 1.2 1.21 1.22 1.23) (5.0 5.01 4.98))
This result is right.
_$ (List:DuplicatesEq2 '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 ) 0.05)
((1.19 1.2 1.21 1.22 1.23 1.25))
_$ (List:DuplicatesEq2 '(1.0 1.1 1.19 5.0 5.01 4.98 1.2 1.21 1.22 1.23 1.3) 0.05)
((1.19 1.2 1.21 1.22 1.23) (4.98 5.0 5.01))
xiaxiang
For the sanity of anyone trying to follow this thread perhaps it would be better to start a new thread with the revised requirements rather than just change the first post.
Have a little respect for those who come along later.
OK, here's an iterative + imperative attempt by first sorting the list:Minor errorCode: [Select]_$ (List:DuplicatesEq2 '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 ) 0.05)
((1.19 1.2 1.21 1.22 1.23 1.25))
_$ (List:DuplicatesEq2 '(1.0 1.1 1.19 5.0 5.01 4.98 1.2 1.21 1.22 1.23 1.3) 0.05)
((1.19 1.2 1.21 1.22 1.23) (4.98 5.0 5.01))
(List:DuplicatesEq2 '(1.0 1.1 1.19 1.2 1.2 1.21 1.22 1.23 1.25 1.3 2.0 2.1 2.19 2.2 2.2 2.21 2.22 2.23 2.25 2.3) 0.05)
-->((1.19 1.2 1.2 1.21 1.22 1.23 1.25) (2.19 2.2 2.2 2.21 2.22 2.23 2.25 2.3))
Minor errorCode: [Select](List:DuplicatesEq2 '(1.0 1.1 1.19 1.2 1.2 1.21 1.22 1.23 1.25 1.3 2.0 2.1 2.19 2.2 2.2 2.21 2.22 2.23 2.25 2.3) 0.05)
-->((1.19 1.2 1.2 1.21 1.22 1.23 1.25) (2.19 2.2 2.2 2.21 2.22 2.23 2.25 [color=red]2.3[/color]))
(equal 2.25 2.3 0.05);=>> T
(equal 2.15 2.2 0.05);=>> nil
(equal 2.05 2.1 0.05);=>> nil
:-(
my version for sorted list:Code - Auto/Visual Lisp: [Select]test:
) )Code - Auto/Visual Lisp: [Select]
What is "a" and "b"? :-o
(f (vl-sort '(1.0 1.1 1.19 1.2 1.2 1.21 1.22 1.23 1.25 1.3 2.0 2.1 2.19 2.2 2.2 2.21 2.22 2.23 2.25 2.3) '<=) 0.05 nil)
On my comp:butCode: [Select](equal 2.25 2.3 0.05);=>> T
:-(
(equal 2.15 2.2 0.05);=>> nil
(equal 2.05 2.1 0.05);=>> nil
(equal 2.25 (+ 2.25 0.05) 0.05);=>> Tdamn nice surprise from autodesk programmers :)
(equal 2.15 (+ 2.15 0.05) 0.05);=>> T
(equal 2.05 (+ 2.05 0.05) 0.05);=>> T
;; Unique with Fuzz - Lee Mac
;; Returns a list with all elements considered duplicate to
;; a given tolerance removed.
(defun LM:UniqueFuzz ( l f / x r )
(while l
(setq x (car l)
l (vl-remove-if (function (lambda ( y ) (equal x y f))) (cdr l))
r (cons x r)
)
)
(reverse r)
)
(LM:UniqueFuzz '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3) 0.05)
=> (1.0 1.1 1.19 1.25 1.3)
So: (1.2 1.21 1.22 1.23) are duplicates? This is the required result?; 20150114 - 1.00 - only for test
(defun ALE_List_FindDupesFuzz (In_Lst FuzFac / OutLst TmpLst NthVal Countr)
(setq OutLst (list (car In_Lst)) In_Lst (cdr In_Lst))
(foreach ForElm In_Lst
(if (vl-position ForElm OutLst)
OutLst
(progn
(setq Countr 0)
(while (and Countr (setq NthVal (nth Countr OutLst)))
(if (equal ForElm NthVal FuzFac)
(setq Countr nil)
(setq Countr (1+ Countr))
)
)
(if NthVal
(setq TmpLst (cons ForElm TmpLst))
(setq OutLst (cons ForElm OutLst))
)
)
)
)
(reverse TmpLst)
)
(ALE_List_FindDupesFuzz '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3) 0.05)
(1.2 1.21 1.22 1.23)
(1.19 1.2 1.21 1.22 1.23 1.25) are duplicate items in my case.The next step we will determine which value that was considered as duplicate should be reserved.Ok, this may be a foreach version:
; 20150115 - 1.03
(defun ALE_List_FindDupesFuzz (In_Lst FuzFac / OutLst TmpLst NthVal Countr)
(setq OutLst (list (car In_Lst)) In_Lst (cdr In_Lst))
(foreach ForElm In_Lst
(if (vl-position ForElm OutLst)
(or (vl-position ForElm TmpLst) (setq TmpLst (cons ForElm TmpLst)))
(progn
(setq Countr 0)
(while (and Countr (setq NthVal (nth Countr OutLst)))
(if (equal ForElm NthVal FuzFac) (setq Countr nil) (setq Countr (1+ Countr)))
)
(or
Countr
(progn
(or (vl-position NthVal TmpLst) (setq TmpLst (cons NthVal TmpLst)))
(and (vl-position NthVal OutLst) (setq OutLst (vl-remove NthVal OutLst)))
)
)
(if NthVal (setq TmpLst (cons ForElm TmpLst)) (setq OutLst (cons ForElm OutLst)))
)
)
)
(reverse TmpLst)
)
Minor errorCode: [Select](List:DuplicatesEq2 '(1.0 1.1 1.19 1.2 1.2 1.21 1.22 1.23 1.25 1.3 2.0 2.1 2.19 2.2 2.2 2.21 2.22 2.23 2.25 2.3) 0.05)
-->((1.19 1.2 1.2 1.21 1.22 1.23 1.25) (2.19 2.2 2.2 2.21 2.22 2.23 2.25 [color=red]2.3[/color]))
On my comp:Code: [Select](equal 2.25 2.3 0.05);=>> T
:(
(equal 2.15 2.2 0.05);=>> nil
(equal 2.05 2.1 0.05);=>> nil
Minor errorCode: [Select](List:DuplicatesEq2 '(1.0 1.1 1.19 1.2 1.2 1.21 1.22 1.23 1.25 1.3 2.0 2.1 2.19 2.2 2.2 2.21 2.22 2.23 2.25 2.3) 0.05)
-->((1.19 1.2 1.2 1.21 1.22 1.23 1.25) (2.19 2.2 2.2 2.21 2.22 2.23 2.25 [color=red]2.3[/color]))
On my comp:Code: [Select](equal 2.25 2.3 0.05);=>> T
:(
(equal 2.15 2.2 0.05);=>> nil
(equal 2.05 2.1 0.05);=>> nil
Same here .. that's not cool.
(equal 2.25 2.30 0.05) ;=>> T
(equal 2.25 2.30 0.049999999999999) ;=>> nil
(equal 2.25 2.30 0.0499999999999999) ;=>> T
(equal 2.15 2.2 0.05) ;=>> nil
(equal 2.15 2.2 0.0500000000000001) ;=>> nil
(equal 2.15 2.2 0.050000000000001) ;=>> T
:?
(setq fuzz 0.05 alist '(3.0 1.0 1.1 1.19 1.2 1.21 1.22 3.0 3.0 3.0 3.0 3))
=> (3.0 1.0 1.1 1.19 1.2 1.21 1.22 3.0 3.0 3.0 3.0 3)
(ALE_List_FindDupesFuzz alist fuzz) >>> r.1.03
=> (1.19 1.2 1.21 1.22 3.0 3)
(f (vl-sort alist '<=) fuzz nil)
=> ((1.19 1.2 1.21 1.22) (3 3.0 3.0 3.0 3.0 3.0))
(List:DuplicatesEq alist fuzz)
=> (3.0 1.19 1.2 1.21 1.22 3.0 3.0 3.0 3.0 3)
This problem is caused by the fact that the 64 bit binary floating point format (http://en.wikipedia.org/wiki/Floating_point) cannot be exactly matched to the decimal format.On my comp:butCode: [Select](equal 2.25 2.3 0.05);=>> T
:-(
(equal 2.15 2.2 0.05);=>> nil
(equal 2.05 2.1 0.05);=>> nilQuote(equal 2.25 (+ 2.25 0.05) 0.05);=>> Tdamn nice surprise from autodesk programmers :)
(equal 2.15 (+ 2.15 0.05) 0.05);=>> T
(equal 2.05 (+ 2.05 0.05) 0.05);=>> T
=> fuzz 0.05
Remove Uniques: (1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0)
=>(1.2 1.21 1.22 1.23)
Show Dupes: (1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0)
=> ( 1.19 1.2 1.21 1.22 1.23 1.25 3.0)
Show All Dupes: (1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0)
=> ( 1.19 1.2 1.21 1.22 1.23 1.25 3.0 3.0 3.0)
IMHO, I think to properly terminate this thread need to distinguish three types of "ListDupesFuzz" functions:Code: [Select]=> fuzz 0.05
Remove Uniques: (1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0)
=>(1.2 1.21 1.22 1.23)
Sorry but I couldn't understand the function "Remove Uniques".My apologies the exact result is:
Why does it return (1.2 1.21 1.22 1.23)?
In fact I could not state the situation of the duplicate items exactly yet.
Remove Uniques: (1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0)
=>( 1.2 1.21 1.22 1.23 3.0 3.0)
You can understand what I meant if you see my previous post: http://www.theswamp.org/index.php?topic=48646.msg537421#msg537421 (http://www.theswamp.org/index.php?topic=48646.msg537421#msg537421)(LM:UniqueFuzz ' (1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0) 0.05)
(1.0 1.1 1.19 ^ ^ ^ ^ 1.25 1.3 3.0 ^ ^ )
Remove Uniques:=>( 1.2 1.21 1.22 1.23 3.0 3.0)
(LM:UniqueFuzz '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0) 0.05)
=>(1.0 1.1 1.19 ^ ^ ^ ^ 1.25 1.3 3.0 ^ ^ )
(LM:UniqueFuzz '(1.0 1.1 1.2 1.21 1.22 1.23 1.25 1.3 3.0 1.19 3.0 3.0) 0.05)
=>(1.0 1.1 1.2 ^ ^ ^ 1.25 1.3 3.0 ^ ^ ^ )
Here's another ideaIs it right?
...
(setq fuzz 0.05 alist '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0))
=> (1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0)
(group-duplicates alist fuzz)
=> ((1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3) (3.0 3.0 3.0))
(equal 1.1 1.0 0.05) => nil
(equal 1.1 1.19 0.05) => nil
(equal 1.3 1.25 0.05) => nil
(equal 1.3 3.0 0.05) => nil
Is it right?Following ... as I understand this:Code: [Select](group-duplicates alist fuzz)
=> ((1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3) (3.0 3.0 3.0))
(group-duplicates alist fuzz)
=> ((1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3) (3.0 3.0 3.0))
This one I do see that I make a mistake. Will have to look at how to get around it without making a huge extra iteration just for that edge case.Code: [Select](equal 1.1 1.19 0.05) => nil
Floating point inacuracies. I use a division on the fuzz, that's why in my defun that is considered equal. It's just an implementation issue.Code: [Select](equal 1.3 1.25 0.05) => nil
I don't understand. Isn't that exactly what my defun did?Code: [Select](equal 1.1 1.0 0.05) => nil
(equal 1.3 3.0 0.05) => nil
Yes, I just wanted to say that:I don't understand. Isn't that exactly what my defun did?Code: [Select](equal 1.1 1.0 0.05) => nil
(equal 1.3 3.0 0.05) => nil
for 1.1 >>> 1.0 is the the nearest lower (equal 1.1 1.0 0.05) => nil
for 1.1 >>> 1.19 is the closest top (equal 1.1 1.19 0.05) => nil
for 1.3 >>> 1.25 is the the nearest lower (equal 1.3 1.25 0.05) => nil
for 1.3 >>> 3.0 is the closest top (equal 1.3 3.0 0.05) => nil
_$ (group-duplicates1 '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0) 0.05)
((1.19 1.2) (1.25 1.21 1.22 1.23) (3.0 3.0 3.0))
Seems to work:Hang-on ... that's even worse isn't it!Code: [Select]_$ (group-duplicates1 '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0) 0.05)
((1.19 1.2) (1.25 1.21 1.22 1.23) (3.0 3.0 3.0))
_$ (group-duplicates2 '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0) 0.05)
((1.19 1.2 1.21 1.22 1.23 1.25) (3.0 3.0 3.0))
(defun ALE_List_ShowDupesFuzz (In_Lst FuzFac / For001 For002 OutLst)
(foreach ForElm (mapcar '(lambda (x) (nth x In_Lst)) (vl-sort-i In_Lst '<))
(and
(or (equal ForElm For001 FuzFac) (and For001 (equal For001 For002 FuzFac)))
(setq OutLst (cons For001 OutLst))
)
(setq For002 For001 For001 ForElm)
)
(if (equal For001 For002 FuzFac) (reverse (cons For001 OutLst)) (reverse OutLst))
)
(setq fuzz 0.05 alist '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0))
(ALE_List_ShowDupesFuzz alist fuzz)
=>(1.19 1.2 1.21 1.22 1.23 1.25 3.0 3.0 3.0)
; Function: ALE_List_RemoveAllDupesFuzz - Version 1.01 - 2015/01/21
;
(defun ALE_List_RemoveAllDupesFuzz (In_Lst FuzFac / For001 For002 OutLst )
(foreach ForElm (mapcar '(lambda (x) (nth x In_Lst)) (vl-sort-i In_Lst '<))
(and
For001
(or
(equal ForElm For001 FuzFac) (equal For001 For002 FuzFac)
(setq OutLst (cons For001 OutLst))
)
)
(setq For002 For001 For001 ForElm)
)
(if (equal For001 For002 FuzFac) (reverse OutLst) (reverse (cons For001 OutLst)))
)
(setq fuzz 0.05 alist '(1.0 1.1 1.19 1.2 1.21 1.22 1.23 1.25 1.3 3.0 3.0 3.0))
=> (1.0 1.1 1.3)