llsheng_73 发表于 2022-9-17 09:04:07

N维表排序及自定义顺序

本帖最后由 llsheng_73 于 2022-9-19 17:55 编辑

对一维表排序简单,(vl-sort l '<)

对二维表复杂点,通常写法(vl-sort l'(lambda(x y)(if(=(car x)(car y))(<(cadr x)(cadr y)(<(car x)(car y)))
那么对于三维甚至多维呢?难道象二维表那样一直套下去?
当然不是不行,但存在的问题很明显,一是不能通用,二是代码很长,多维应该能把自己先搞晕。
如果反过来,对排序参数x,y先去除相同的,再对它们进行排序是不是就可以通用了呢?
有想法就上码,经测试想法是正确的
(defun sortn(l fun)
(vl-sort l'(lambda(x y)(while(and(=(car x)(car y))(cdr x)(cdr y))(setq x(cdr x)y(cdr y)))(fun(car x)(car y)))))
这样虽然解决了二维到多维的问题,但明显不支持一维表排序了
(defun sortn(l fun)
(or(listp(car l))(setq l(mapcar'list l)))
(vl-sort l'(lambda(x y)(while(and(=(car x)(car y))(cdr x)(cdr y))(setq x(cdr x)y(cdr y)))(fun(car x)(car y)))))
但缺点同样明显,所有维数的排序依据都是相同的,如果要按指定维数指定依据的话,首先应该按维数给定排序依据,即 fun应该为funs
(defun sortn(l funs)
(or(listp(car l))(setq l(mapcar'list l)))
(or(listp funs)(setq funs(list funs)))
(while(<(length funs)(length(car l)))
    (setq funs(cons(car funs)funs)))
(vl-sort l'(lambda(x y / n)(setq n 0)
       (while(and(=(car x)(car y))(cdr x)(cdr y))(setq x(cdr x)y(cdr y)n(1+ n)))((nth n funs)(car x)(car y)))))
对于菜卷鱼提出的很关键的一个问题,先排序第几维,另外根据masterlong的思路,增加容差,并修改为只排序指定维数
再增加一个自定义序列支持,让就它彻底成为EXCEL的排序吧,感觉白折腾了
(defun sortn(l keys funs fuzz / n mposition);;;keys关键字列号要么为nil要么为表,funs各个关键字的排序方式,通常为<或>,也可以为自定义序列,比如'("张三""李四")
(defun mposition(e l / i)(if(setq i(vl-position e l))i(length l)))
(or(listp(car l))(setq l(mapcar'list l)))
(or(listp funs)(setq funs(list funs)))
(if(zerop(setq n(length keys)))(setq n(length(car l))))
(while(<(length funs)n)(setq funs(cons(car funs)funs)))
(mapcar(function(lambda(x)(nth x l)))
         (vl-sort-i(if keys(mapcar(function(lambda(x)(mapcar'(lambda(y)(nth y x))keys)))l)l)
                   (function(lambda(x y / n )(setq n 0)
                      (while(and(equal(car x)(car y)fuzz)(cdr x)(cdr y))(setq x(cdr x)y(cdr y)n(1+ n)))
                              (if(listp(setq n(nth n funs)))
                              (<(mposition(car x)n)(mposition(car y)n))
                              (n(car x)(car y))))))))
对于需要排序的表比较大的情况,是否可以考虑直接调用EXCEL来排序?

(SORTN '((2 2 3 4)(1 1 1 7)(2 2 1 5)(1 1 0 4))'(1 3)(list > <)0)
((2 2 3 4) (2 2 1 5) (1 1 0 4) (1 1 1 7))


(SORTN'(("上海""崇明区")("北京""朝阳区")("上海""静安区")("北京""房山区")("重庆""酉阳")("四川""成都"))nil'(("北京""上海")("静安区""朝阳区""房山区""崇明区""成都""酉阳"))0)
(("北京" "朝阳区") ("北京" "房山区") ("上海" "静安区") ("上海" "崇明区") ("四川" "成都") ("重庆" "酉阳"))











masterlong 发表于 2022-9-19 14:32:28

本帖最后由 masterlong 于 2022-9-19 14:59 编辑


;999公共函数
;|
my_px   给定排序优先级和排序方式,对多维坐标表进行排序
(my_px pobiao biao1 biao2 fuzz)

pobiao----点坐标集合,每一个元素均为n维坐标点
biao1-----每一维的排序优先级,是一个0~n-1的整数表,数字越小级别越高。如'(1 2 0) 表示Z优先级最高,X其次,Y最低
biao2-----各维的排序关系,元素个数n-1,元素为“>”或“<”。如'(> > <) 表示X按大小排序,Y按大小排序,Z按小大排序
fuzz------容差值。

实例:
二维坐标从上到下从左到右,容差为0【这是人阅读的习惯模式】
(my_px '((6 4)(7 3)(6 2)(7 9)(2 2)(1 6)) '(1 0) '(< >) 0)
返回:((7 9) (1 6) (6 4) (7 3) (2 2) (6 2))

实例:
二维坐标从上到下从左到右,容差为1
(my_px '((6 4)(7 3)(6 2)(7 9)(2 2)(1 6)) '(1 0) '(< >) 1)
返回:((7 9) (1 6) (6 4) (2 2) (6 2) (7 3))

实例:
四维坐标指定方式排序
(my_px '((2 2 3 4)(1 1 1 7)(2 2 1 5)(1 1 0 4)) '(2 1 0 3) '(< > > <) 0)
返回:((2 2 3 4) (2 2 1 5) (1 1 1 7) (1 1 0 4))
|;
;;
(defun my_px( pobiao biao1 biao2 fuzz )
(vl-sort pobiao
   ''((a b)
          (setq n (length biao1))
          (setq i 0)
          (while (< i n)
            (setq id (vl-position i biao1))    ;;比较维度
            (setq bj (nth id biao2))         ;;比较符号
            
            ;;ab比较
            (setq aa (nth id a))
            (setq bb (nth id b))
            (if (> (abs (- aa bb)) fuzz)
            (progn
                (setq i n)
                ((eval bj) aa bb)
            )
            (setq i (1+ i))
            )
          )
   )
)
)


masterlong 发表于 2022-9-19 15:05:45

;999公共函数
;|
my_px_v2   给定排序优先级和排序方式,对多维坐标表进行排序   (允许对某个维度忽略排序)
(my_px_v2 pobiao biao1 biao2 fuzz)

pobiao----点坐标集合,每一个元素均为n维坐标点
biao1-----每一维的排序优先级,是一个0~n-1的整数表,数字越小级别越高。如'(1 2 0) 表示Z优先级最高,X其次,Y最低
biao2-----各维的排序关系,元素个数n-1,元素为“>”或“<”或nil,nil表示对应维度不排序。如'(> > nil) 表示X按大小排序,Y按大小排序,Z不进行排序
fuzz------容差值。

实例:
二维坐标从上到下从左到右,容差为0【这是人阅读的习惯模式】
(my_px_v2 '((6 4)(7 3)(6 2)(7 9)(2 2)(1 6)) '(1 0) '(< >) 0)
返回:((7 9) (1 6) (6 4) (7 3) (2 2) (6 2))

实例:
二维坐标从上到下从左到右,容差为1
(my_px_v2 '((6 4)(7 3)(6 2)(7 9)(2 2)(1 6)) '(1 0) '(< >) 1)
返回:((7 9) (1 6) (6 4) (2 2) (6 2) (7 3))

实例:
四维坐标指定方式排序1
(my_px_v2 '((2 2 3 4)(1 1 1 7)(2 2 1 5)(1 1 0 4)) '(2 1 0 3) '(< > > <) 0)
返回:((2 2 3 4) (2 2 1 5) (1 1 1 7) (1 1 0 4))

实例:
四维坐标指定方式排序2
(my_px_v2 '((2 2 3 4)(1 1 1 7)(2 2 1 5)(1 1 0 4)) '(2 1 0 3) '(< > < <) 0)
返回:((1 1 0 4) (2 2 1 5) (1 1 1 7) (2 2 3 4))

实例:
四维坐标指定方式排序3
(my_px_v2 '((2 2 3 4)(1 1 1 7)(2 2 1 5)(1 1 0 4)) '(2 1 0 3) '(< > nil <) 0)
返回:((2 2 3 4) (2 2 1 5) (1 1 0 4) (1 1 1 7))
|;
;;
(defun my_px_v2( pobiao biao1 biao2 fuzz / n i id bj aa bb )
(vl-sort pobiao
      ''((a b)
            (setq n (length biao1))
            (setq i 0)
            (while (< i n)
            (setq id (vl-position i biao1))    ;;比较维度
            (setq bj (nth id biao2))            ;;比较符号
            
            ;;ab比较
            (if (null bj)
                (setq i (1+ i))
                (progn
                  (setq aa (nth id a))
                  (setq bb (nth id b))
                  (if (> (abs (- aa bb)) fuzz)
                  (progn
                      (setq i n)
                      ((eval bj) aa bb)
                  )
                  (setq i (1+ i))
                  )
                )
            )
            )
      )
)
)

菜卷鱼 发表于 2022-9-17 09:41:21

你这个问题问得很抽象
一维表排序好说,就1个数字,可以直接排序
二维表就说不通了,是先排X位呢,还是先排Y位
三维表也是,X,Y,Z先排哪个总得有个顺序吧?

llsheng_73 发表于 2022-9-17 09:48:03

菜卷鱼 发表于 2022-9-17 09:41
你这个问题问得很抽象
一维表排序好说,就1个数字,可以直接排序
二维表就说不通了,是先排X位呢,还是先 ...

确实这一点很重要。。。

aihuyujian 发表于 2022-9-17 10:03:30

所以说搞个二维的感觉头都秃了更别说三维了

菜卷鱼 发表于 2022-9-17 10:13:12

l 排序次数
d 排序方向,nil 表示从左至右
f 排序方法 > , <

(setq lst '((1 2 3)(2 3 2)(3 4 1)))
(ldfsort lst 3 nil >) ==>((1 2 3) (2 3 2) (3 4 1))
(ldfsort lst 3 t >)==>((3 4 1) (2 3 2) (1 2 3))


(defun ldfsort (lst l d f / ldf_sort s nf lst)
(defun ldf_sort (lst n f)
    (vl-sort lst '(lambda (x y) (f (nth n x) (nth n y))))
)
(if (null d)
    (setq s-1
          nf 1+
    )
    (setq sl
          nf 1-
    )
)
(repeat l
    (setq s (nf s))
    (setq lst (ldf_sort lst s f))
)
)

llsheng_73 发表于 2022-9-17 10:17:09

aihuyujian 发表于 2022-9-17 10:03
所以说搞个二维的感觉头都秃了更别说三维了

按L表中各维顺序给定排序依据,按排序优先次序给出sorts
对于先Y按增加x按减来说 (sortn l '(1 0) (list < >))

guosheyang 发表于 2022-9-19 14:49:17

masterlong 发表于 2022-9-19 14:32


感谢优化,加上了容差   代码好像更简洁了

masterlong 发表于 2022-9-19 15:34:11

73兄的代码看着费劲
执行效率比我的高

(progn
        (time_start)
        (repeat 50000 (my_px '((2 2 3 4)(1 1 1 7)(2 2 1 5)(1 1 0 4)) '(2 1 0 3) '(< > > <) 0))
        (time_end)
)
********程序运行完成   耗时 28.07 秒********

(progn
        (time_start)
        (repeat 50000 (SORTN '((2 2 3 4)(1 1 1 7)(2 2 1 5)(1 1 0 4)) '(2 1 0 3) (list < >> <)))
        (time_end)
)
********程序运行完成   耗时 5.44 秒********

差距还挺大
是我的代码里nth用的比较多?
页: [1] 2
查看完整版本: N维表排序及自定义顺序