求排序算法

FainSheeg 2019-04-28 10:24:50
现在有一个自定义类JBScore做为model:

public class JBScore extends LitePalSupport {
private int id;
private String icd;
private String jbname;
private String sscode;
private String ssname;
private int sscount;
private int score;
public int getId(){return id;}
public void setId(int id){this.id=id;}
public String getICD(){return icd;}
public void setICD(String icd){this.icd=icd;}
public String getJbname(){return jbname;}
public void setJbname(String jbname){this.jbname=jbname;}
public String getSSCode(){return sscode;}
public void seSSCode(String sscode){this.sscode=sscode;}
public String getSSName(){return ssname;}
public void setSSName(String ssname){this.ssname=ssname;}
public int getSSCount(){return sscount;}
public void setSSCount(int sscount){this.sscount=sscount;}
public int getScore(){return score;}
public void setScore(int score){this.score=score;}
}

现在要根据JBScore的icd,sscount,score排序,要求:
1.当icd相同时,首先根据sscount倒序,sscount相同时根据score倒序。
2.当icd不同时,首先按score倒序,score相同时按sscount倒序。

下面是我的实现代码:

jbList.sort(new Comparator<JBScore>() {
@Override
public int compare(JBScore jbScore, JBScore t1) {
//如果icd相同
if(jbScore.getICD()==t1.getICD()){
//先比较sscount
if (jbScore.getSSCount()>t1.getSSCount()){return 1;}//sscount大的排前面
if (jbScore.getSSCount()<t1.getSSCount()){return -1;}//sscount小的排 后面
if (jbScore.getSSCount()==t1.getSSCount()){
//sscount相同时比较score
if (jbScore.getScore()>t1.getScore()){ return 1; }
else if (jbScore.getScore()==t1.getScore()){ return 0; }
else { return -1; }
}
}
else {
//如果icd不同则先对比score
if (jbScore.getScore()>t1.getScore()){return 1;}
else if (jbScore.getScore()<t1.getScore()){return -1;}
else {
//score相同则对比sscount
if (jbScore.getSSCount()>t1.getSSCount()){return 1;}
else if (jbScore.getSSCount()<t1.getSSCount()){return -1;}
else {return jbScore.getICD().compareTo(t1.getICD());}
}
}
return 0;
}
});


但这个代码有个Bug:
当有以下三个实体数据时,没有达到预期:
id icd sscount score
1 a 2 10
2 a 1 30
3 b 1 20

按我的代码排序为:1>2>3
而我想要的是:3>1>2
...全文
318 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
浪费七年时间 2019-04-29
  • 打赏
  • 举报
回复
引用 13 楼 浪费七年时间 的回复:
感觉你的排序逻辑有问题,因为既然你加入了icd作为比较条件,那你就肯定要指定icd是升序或是降序,而不是单纯的相同或不同
排序就是要有三种结果"大于、小于和等于",而不是"等于和不等于"
浪费七年时间 2019-04-29
  • 打赏
  • 举报
回复
感觉你的排序逻辑有问题,因为既然你加入了icd作为比较条件,那你就肯定要指定icd是升序或是降序,而不是单纯的相同或不同
浪费七年时间 2019-04-29
  • 打赏
  • 举报
回复
16楼贴的代码里19行到30行改成下面的,并行流直接往ArrayList里面add会有线程安全问题

	List<List<JBScore>> groups = list.stream()
		.collect(Collectors.groupingBy(JBScore::getIcd))
		.values().parallelStream()
		.map(l -> {
			return l.stream().sorted(
					Comparator
					.comparing(JBScore::getSscount, Comparator.reverseOrder())
					.thenComparing(JBScore::getScore, Comparator.reverseOrder())
			).collect(Collectors.toList());
		})
		.collect(Collectors.toList());
gencin 2019-04-29
  • 打赏
  • 举报
回复
你给的例子中,显然排序的结果不是唯一的。还需要添加条件
浪费七年时间 2019-04-29
  • 打赏
  • 举报
回复
引用 15 楼 FainSheeg 的回复:
[quote=引用 14 楼 浪费七年时间 的回复:] [quote=引用 13 楼 浪费七年时间 的回复:] 感觉你的排序逻辑有问题,因为既然你加入了icd作为比较条件,那你就肯定要指定icd是升序或是降序,而不是单纯的相同或不同
排序就是要有三种结果"大于、小于和等于",而不是"等于和不等于"[/quote] ......我又不是按icd排序,icd同与不同只是区别不同的排序算法而已。[/quote] 如果是按你说的根据ICD分组后,分组内按1进行排序,分组外取每个组第一条按2进行组的排序,那样的话是能实现的,Java8的stream和sorted就很方便

	@Test
	@SuppressWarnings("unchecked")
	public void testCmp() {
		JBScore score1 = new JBScore(1, "a", 2, 20);
		JBScore score2 = new JBScore(2, "a", 1, 20);
		JBScore score3 = new JBScore(3, "a", 2, 30);//a组第一个元素
		
		JBScore score4 = new JBScore(4, "b", 2, 10);
		JBScore score5 = new JBScore(5, "b", 3, 10);//b组第一个元素
		JBScore score6 = new JBScore(6, "b", 2, 20);
		
		JBScore score7 = new JBScore(7, "c", 3, 30);//c组第一个元素
		JBScore score8 = new JBScore(8, "c", 3, 20);
		JBScore score9 = new JBScore(9, "c", 1, 30);
		//最终c  a b -> (7 8 9) (3 1 2) (5 6 4)

		List<JBScore> list = Arrays.asList(new JBScore[] { score1, score2, score3, score4, score5, score6, score7, score8, score9});
		
		List<List<JBScore>> groups = new ArrayList<>();
		
		list.parallelStream()
		.collect(Collectors.groupingBy(JBScore::getIcd))
		.values().parallelStream()
		.forEach(l -> {
				groups.add(l.stream().sorted(
						Comparator
						.comparing(JBScore::getSscount, Comparator.reverseOrder())
						.thenComparing(JBScore::getScore, Comparator.reverseOrder())
				).collect(Collectors.toList()));
		});
		
		List<JBScore> result = groups.stream()
				.sorted(
						Comparator
						.comparing(t -> ((List<JBScore>) t).get(0).getScore(), Comparator.reverseOrder())
						.thenComparing(t -> ((List<JBScore>) t).get(0).getSscount(), Comparator.reverseOrder())
				)
				.flatMap(List::stream)
				.collect(Collectors.toList());
		
		for (JBScore jbScore : result) {
			System.err.println(jbScore);
		}
	}
FainSheeg 2019-04-29
  • 打赏
  • 举报
回复
引用 14 楼 浪费七年时间 的回复:
[quote=引用 13 楼 浪费七年时间 的回复:]
感觉你的排序逻辑有问题,因为既然你加入了icd作为比较条件,那你就肯定要指定icd是升序或是降序,而不是单纯的相同或不同

排序就是要有三种结果"大于、小于和等于",而不是"等于和不等于"[/quote]
......我又不是按icd排序,icd同与不同只是区别不同的排序算法而已。
FainSheeg 2019-04-28
  • 打赏
  • 举报
回复
引用 4 楼 水边2 的回复:
你说:而我想要的是:3>1>2
那2明明是大于3的,怎么跑到后面去了……

其实我在1#有补充说明,先进行icd相同的排序,icd相同的排好后,再进行icd不同的排序,当icd不同时(a,b),那么(b根a那一组的排第一的对比结果)优先级要高。
游北亮 2019-04-28
  • 打赏
  • 举报
回复
你说:而我想要的是:3>1>2 那2明明是大于3的,怎么跑到后面去了……
游北亮 2019-04-28
  • 打赏
  • 举报
回复
你的需求是有悖论的,按你的举例数据: 1和2的icd相同,所以sscount倒序后是 1,2 2和3的icd不同,所以score倒序后是 2,3 1和3的icd不同,所以score倒序后是 3,1 那1到底应该在最前面,还是最后面呢? 明显是需求的问题,需求不改无解,改需求吧。
FainSheeg 2019-04-28
  • 打赏
  • 举报
回复
感觉好像单纯的自定义一个Comparator很难达到目的。
FainSheeg 2019-04-28
  • 打赏
  • 举报
回复
按我的代码算的话:1>2,2>3,3>1所以就乱了,我要的是当icd不同时(a,b),那么b根a那一组的第一个的对比结果优先级要高。
FainSheeg 2019-04-28
  • 打赏
  • 举报
回复
引用 11 楼 nayi_224 的回复:
[quote=引用 9 楼 FainSheeg 的回复:]
[quote=引用 8 楼 nayi_224 的回复:]
20肯定是排在10和30中间,你怎么排到第一位去了?
难道是先对icd相同的进行排序,然后作为整体去跟20进行比较?

3和1比较,按照第二条规则icd不同时,score大的排前面,所以20排10前面[/quote]
那3为什么不和2去比较?[/quote]
也要啊,所以才会达不到预期呀,所以来这里求教大神啊
nayi_224 2019-04-28
  • 打赏
  • 举报
回复
引用 9 楼 FainSheeg 的回复:
[quote=引用 8 楼 nayi_224 的回复:] 20肯定是排在10和30中间,你怎么排到第一位去了? 难道是先对icd相同的进行排序,然后作为整体去跟20进行比较?
3和1比较,按照第二条规则icd不同时,score大的排前面,所以20排10前面[/quote] 那3为什么不和2去比较?
FainSheeg 2019-04-28
  • 打赏
  • 举报
回复
引用 7 楼 qps2009 的回复:
我理解的楼主的意思是这样的: 将icd 相同的分配到一组里面,分成若干组后,每个组里面按下面的规则排序:
当icd相同时,首先根据sscount倒序,sscount相同时根据score倒序。
然后再将这个若干个组进行排序,排序的规则如下:
将这若干个组的首个元素,取出来首先按score倒序,score相同时按sscount倒序,以此决定这若干个组的次序。
最后再按顺序将每个组的每个元素输出就是排序后的结果。
还有,楼主的Comparator的返回值是不是写反了,如果按倒序排序的话,即大的元素排前面,如果比较结果大于0的话,应该是返回-1吧?
最后贴上代码,用了两个Comparator
import java.util.Comparator;

public class JBComparator implements Comparator<JBScore> {
@Override
public int compare(JBScore o1, JBScore o2) {
if (o1.getSSCount()>o2.getSSCount()){return -1;}//sscount大的排前面
if (o1.getSSCount()<o2.getSSCount()){return 1;}//sscount小的排 后面
if (o1.getSSCount()==o2.getSSCount()){
//sscount相同时比较score
if (o1.getScore()>o2.getScore()){ return -1; }
else if (o1.getScore()==o2.getScore()){ return 0; }
else { return 1; }
}
return 0;
}
}

import java.util.Comparator;
import java.util.List;

public class JBListComparator implements Comparator<List<JBScore>> {
@Override
public int compare(List<JBScore> o1, List<JBScore> o2) {
JBScore jbScore1 = o1.get(0);
JBScore jbScore2 = o2.get(0);
//如果icd不同则先对比score
if (jbScore1.getScore()>jbScore2.getScore()){return -1;}
else if (jbScore1.getScore()<jbScore2.getScore()){return 1;}
else {
//score相同则对比sscount
if (jbScore1.getSSCount()>jbScore2.getSSCount()){return -1;}
else if (jbScore1.getSSCount()<jbScore2.getSSCount()){return 1;}
else {return jbScore1.getICD().compareTo(jbScore2.getICD());}
}
}
}


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Test {
public static List<JBScore> sortJB(List<JBScore> list){
List<List<JBScore>> lists = new ArrayList<>();
List<String> stringList = new ArrayList<>();
for(JBScore jbScore:list){
if(!stringList.contains(jbScore.getICD()))
stringList.add(jbScore.getICD());
}
for(int i=0;i<stringList.size();i++){
List<JBScore> jbScoreList = new ArrayList<>();
for(JBScore jbScore:list){
if(jbScore.getICD().equals(stringList.get(i)))
jbScoreList.add(jbScore);
}
Collections.sort(jbScoreList,new JBComparator());
lists.add(jbScoreList);
}
Collections.sort(lists,new JBListComparator());
List<JBScore> result = new ArrayList<>();
for(List<JBScore> list1:lists){
for(JBScore jbScore:list1){
result.add(jbScore);
}
}
return result;
}

public static void main(String[] args){
JBScore jbScore1 = new JBScore();
jbScore1.setId(1);
jbScore1.setICD("a");
jbScore1.setSSCount(2);
jbScore1.setScore(10);
JBScore jbScore2 = new JBScore();
jbScore2.setId(2);
jbScore2.setICD("a");
jbScore2.setSSCount(1);
jbScore2.setScore(30);
JBScore jbScore3 = new JBScore();
jbScore3.setId(3);
jbScore3.setICD("b");
jbScore3.setSSCount(1);
jbScore3.setScore(20);
// JBScore jbScore4 = new JBScore();
// jbScore4.setId(4);
// jbScore4.setICD("b");
// jbScore4.setSSCount(2);
// jbScore4.setScore(10);
List<JBScore> list = new ArrayList<>();
list.add(jbScore1);
list.add(jbScore2);
list.add(jbScore3);
//list.add(jbScore4);
for(JBScore jbScore:list){
System.out.print(jbScore.getId()+" ");
}
System.out.println();
System.out.println("排序后");
List<JBScore> list1 = sortJB(list);
for(JBScore jbScore:list1){
System.out.print(jbScore.getId()+" ");
}
System.out.println();
}
}

先感谢你费心写了这么长的代码,我回去测试一下看看
FainSheeg 2019-04-28
  • 打赏
  • 举报
回复
引用 8 楼 nayi_224 的回复:
20肯定是排在10和30中间,你怎么排到第一位去了?
难道是先对icd相同的进行排序,然后作为整体去跟20进行比较?

3和1比较,按照第二条规则icd不同时,score大的排前面,所以20排10前面
nayi_224 2019-04-28
  • 打赏
  • 举报
回复
20肯定是排在10和30中间,你怎么排到第一位去了? 难道是先对icd相同的进行排序,然后作为整体去跟20进行比较?
qps2009 2019-04-28
  • 打赏
  • 举报
回复
我理解的楼主的意思是这样的: 将icd 相同的分配到一组里面,分成若干组后,每个组里面按下面的规则排序: 当icd相同时,首先根据sscount倒序,sscount相同时根据score倒序。 然后再将这个若干个组进行排序,排序的规则如下: 将这若干个组的首个元素,取出来首先按score倒序,score相同时按sscount倒序,以此决定这若干个组的次序。 最后再按顺序将每个组的每个元素输出就是排序后的结果。 还有,楼主的Comparator的返回值是不是写反了,如果按倒序排序的话,即大的元素排前面,如果比较结果大于0的话,应该是返回-1吧? 最后贴上代码,用了两个Comparator
import java.util.Comparator;

public class JBComparator implements Comparator<JBScore> {
    @Override
    public int compare(JBScore o1, JBScore o2) {
        if (o1.getSSCount()>o2.getSSCount()){return -1;}//sscount大的排前面
        if (o1.getSSCount()<o2.getSSCount()){return 1;}//sscount小的排 后面
        if (o1.getSSCount()==o2.getSSCount()){
            //sscount相同时比较score
            if (o1.getScore()>o2.getScore()){ return -1; }
            else if (o1.getScore()==o2.getScore()){ return 0; }
            else { return 1; }
        }
        return 0;
    }
}
import java.util.Comparator;
import java.util.List;

public class JBListComparator implements Comparator<List<JBScore>> {
    @Override
    public int compare(List<JBScore> o1, List<JBScore> o2) {
        JBScore jbScore1 = o1.get(0);
        JBScore jbScore2 = o2.get(0);
        //如果icd不同则先对比score
        if (jbScore1.getScore()>jbScore2.getScore()){return -1;}
        else if (jbScore1.getScore()<jbScore2.getScore()){return 1;}
        else {
            //score相同则对比sscount
            if (jbScore1.getSSCount()>jbScore2.getSSCount()){return -1;}
            else if (jbScore1.getSSCount()<jbScore2.getSSCount()){return 1;}
            else {return jbScore1.getICD().compareTo(jbScore2.getICD());}
        }
    }
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Test {
    public static List<JBScore> sortJB(List<JBScore> list){
        List<List<JBScore>> lists = new ArrayList<>();
        List<String> stringList = new ArrayList<>();
        for(JBScore jbScore:list){
            if(!stringList.contains(jbScore.getICD()))
                stringList.add(jbScore.getICD());
        }
        for(int i=0;i<stringList.size();i++){
            List<JBScore> jbScoreList = new ArrayList<>();
            for(JBScore jbScore:list){
                if(jbScore.getICD().equals(stringList.get(i)))
                    jbScoreList.add(jbScore);
            }
            Collections.sort(jbScoreList,new JBComparator());
            lists.add(jbScoreList);
        }
        Collections.sort(lists,new JBListComparator());
        List<JBScore> result = new ArrayList<>();
        for(List<JBScore> list1:lists){
            for(JBScore jbScore:list1){
                result.add(jbScore);
            }
        }
        return result;
    }
    
    public static void main(String[] args){
        JBScore jbScore1 = new JBScore();
        jbScore1.setId(1);
        jbScore1.setICD("a");
        jbScore1.setSSCount(2);
        jbScore1.setScore(10);
        JBScore jbScore2 = new JBScore();
        jbScore2.setId(2);
        jbScore2.setICD("a");
        jbScore2.setSSCount(1);
        jbScore2.setScore(30);
        JBScore jbScore3 = new JBScore();
        jbScore3.setId(3);
        jbScore3.setICD("b");
        jbScore3.setSSCount(1);
        jbScore3.setScore(20);
//        JBScore jbScore4 = new JBScore();
//        jbScore4.setId(4);
//        jbScore4.setICD("b");
//        jbScore4.setSSCount(2);
//        jbScore4.setScore(10);
        List<JBScore> list = new ArrayList<>();
        list.add(jbScore1);
        list.add(jbScore2);
        list.add(jbScore3);
        //list.add(jbScore4);
        for(JBScore jbScore:list){
            System.out.print(jbScore.getId()+" ");
        }
        System.out.println();
        System.out.println("排序后");
        List<JBScore> list1 = sortJB(list);
        for(JBScore jbScore:list1){
            System.out.print(jbScore.getId()+" ");
        }
        System.out.println();
    }
}
游北亮 2019-04-28
  • 打赏
  • 举报
回复
我记得Array的排序是用的快速排序,而快速排序是不稳定排序,也就是相等的2项,返回顺序无法确定, 你要自己实现排序算法,不能用sort

50,544

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧