问题在于实现Java中优先级队列的自定义比较器

huangapple go评论69阅读模式
英文:

Issue with implementing custom Comparator for Priority Queue in Java

问题

<br/>
请原谅我对Java中优先队列(Priority Queue)和比较器(Comparator)的理解。<br/>
似乎我可以基于某种排序顺序实现基本的优先队列比较器。<br/>
但是我无法为以下情况想出解决方案:<br/>
<ol>

1. 给定一个文件列表,文件名的约定为 xx_yy_zz.dat 。&lt;br/&gt;
2. xx、yy、zz 可以取值从 00 到 50 &lt;br/&gt;
3. 我需要首先处理 xx=30 的文件,其次是 xx=35,然后是 xx=40,最后处理其它文件。&lt;br/&gt;

由于我对优先队列的了解有限,我尝试了一下实现,虽然我能进行升序或降序排列 xx 的值,但这并不符合要求。<br/>
我的方法是
> 将文件名列表放入优先队列,使用正则表达式"_"分割文件名
> 然后使用比较器比较分割数组的第一个索引,基于它的值进行比较,但是如预料的那样,我失败了,因为我的需求与此不同。

请分享一些想法/方法。

不幸的是,似乎我无法为我的情况想出所需的比较器。<br/>
但仍然提前感谢您。

英文:

<br/>
Please pardon my understanding towards priority Queue and Comparator in Java.<br/>
It seems ,I am able to implement basic comparator for Priority Queue based on some sort order.<br/>
But I am not able to come up with something for the below scenario :<br/>
<ol>

1. Given a list of Files with name convention xx_yy_zz.dat .&lt;br/&gt;
2.xx,yy,zz can be from 00-50 &lt;br/&gt;
3.I need to process the files with xx=30 first,xx=35 second xx=40 third and then the rest.&lt;br/&gt;

Since I have limited knowledge with Priority Queue ,I tried to implement it which i was able to sort but only in asc or desc value of xx which was not the requirement.<br/>
My approach was
> put the list of file names in priority Queue ,split the filename on regex "_"
> then compare the first index of split array using comparator based on it values but as expected i failed miserably since my requirement was something different

Please share some ideas/approach.

It seems sadly ,I am not able to come up with the a required comparator for my case .<br/>
Nevertheless thanking you in anticipation

答案1

得分: 1

你可以在compare()方法内部使用简单的if语句,检查一个字符串是否以&quot;30&quot;开头,而另一个字符串则不以此开头。然后你就知道这个字符串必须排在另一个字符串之前。你可以像这样在文件名的第一部分上运行以下if语句:

  1. 他们是否相同?
  2. 左边的是否为30
  3. 右边的是否为30
  4. 左边的是否为35
  5. 右边的是否为35
  6. 左边的是否为40
  7. 右边的是否为40

比较器可能如下所示:

public int compare(String a, String b) {
    String[] splitA = a.split("_");
    String[] splitB = b.split("_");

    if (splitA[0].equals(splitB[0])) {
        return 0;
    }
    if (splitA[0].equals("30")) {
        return -1;
    }
    if (splitB[0].equals("30")) {
        return 1;
    }
    if (splitA[0].equals("35")) {
        return -1;
    }
    if (splitB[0].equals("35")) {
        return 1;
    }
    if (splitA[0].equals("40")) {
        return -1;
    }
    if (splitB[0].equals("40")) {
        return 1;
    }
    return 0;
}

使用以下测试源代码:

System.out.println(Arrays.toString(data));
Arrays.sort(data, new SpecialComparator());
System.out.println(Arrays.toString(data));

你可能会得到类似这样的输出(取决于data数组):

[30_45_35.dat, 00_12_34.dat, 35_50_20.dat, 40_03_05.dat, 33_28_14.dat,
 30_16_31.dat, 20_29_23.dat, 24_41_29.dat, 30_49_18.dat, 40_12_13.dat]

[30_45_35.dat, 30_16_31.dat, 30_49_18.dat, 35_50_20.dat, 40_03_05.dat,
 40_12_13.dat, 00_12_34.dat, 33_28_14.dat, 20_29_23.dat, 24_41_29.dat]

(为了清晰起见,添加了换行符)

正如你所看到的,首先是30,然后是唯一的35,接着是40,最后是其余的内容。如果compareTo方法返回0,你可能想在这些字符串上使用compareTo(),以获得更好的"子排序"效果,这将基于上述基本排序。

英文:

You can use simple if statements inside the compare() method to check if one string starts with &quot;30&quot; and the other does not. Then you know that this string must come before the other one. You run the following if statements like this on the first part of the filenames:

  1. Are they the same?
  2. Is the left one 30?
  3. Is the right one 30?
  4. Is the left one 35?
  5. Is the right one 35?
  6. Is the left one 40?
  7. Is the right one 40?

The comparator might look like this:

public int compare(String a, String b) {
    String[] splitA = a.split(&quot;_&quot;);
    String[] splitB = b.split(&quot;_&quot;);

    if (splitA[0].equals(splitB[0])) {
        return 0;
    }
    if (splitA[0].equals(&quot;30&quot;)) {
        return -1;
    }
    if (splitB[0].equals(&quot;30&quot;)) {
        return 1;
    }
    if (splitA[0].equals(&quot;35&quot;)) {
        return -1;
    }
    if (splitB[0].equals(&quot;35&quot;)) {
        return 1;
    }
    if (splitA[0].equals(&quot;40&quot;)) {
        return -1;
    }
    if (splitB[0].equals(&quot;40&quot;)) {
        return 1;
    }
    return 0;
}

With the following test source code:

System.out.println(Arrays.toString(data));
Arrays.sort(data, new SpecialComparator());
System.out.println(Arrays.toString(data));

You might get an output like this (depending on the data array):

<!-- language: none -->
[30_45_35.dat, 00_12_34.dat, 35_50_20.dat, 40_03_05.dat, 33_28_14.dat,
30_16_31.dat, 20_29_23.dat, 24_41_29.dat, 30_49_18.dat, 40_12_13.dat]

[30_45_35.dat, 30_16_31.dat, 30_49_18.dat, 35_50_20.dat, 40_03_05.dat,
 40_12_13.dat, 00_12_34.dat, 33_28_14.dat, 20_29_23.dat, 24_41_29.dat]

(new lines added for clarity)

As you see you have the 30s first, then the only 35 second, then the 40s third and after that all the remaining stuff. You might want to use compareTo() on the strings in case the compareTo method would return 0 to get better "sub sorting" of strings, which would be equal based on this basic sorting above.

答案2

得分: 0

也许我不太理解您确切的需求... 但是可以尝试这段代码,它会按照开头两位是数字的顺序对字符串进行排序:

public class TrialTest {
    public static void main(String[] args) {

        PriorityQueue<String> q = new PriorityQueue<String>((first, second) -> {
            return Integer.parseInt(first.substring(0, 2)) - Integer.parseInt(second.substring(0, 2));
            //如果您想要逆序排序,只需在返回语句前面加上负号,像这样:
            //return -(Integer.parseInt(first.substring(0, 2)) - Integer.parseInt(second.substring(0, 2)));
        });

        q.add("23lk");
        q.add("22lkjl");
        q.add("45ljl");

        for(String str : q) {
            System.out.println(str);
        }
    }
}

输出结果为:

22lkjl
23lk
45ljl

如果这不是您的解决方案,请详细说明问题,也许我或其他人可以帮助您。

英文:

May be I'm not understand what exactly you need... but simply try this code and it sort me all strings if they has two digits on the begining

    public static void main(String[] args) {



        PriorityQueue&lt;String&gt; q = new PriorityQueue&lt;String&gt;((first, second) -&gt; {
            return Integer.parseInt(first.substring(0, 2)) - Integer.parseInt(second.substring(0, 2));
            //and if you want to reverse order, simply add &quot;-&quot; like this:
            //return -(Integer.parseInt(first.substring(0, 2)) - Integer.parseInt(second.substring(0, 2)));
        });


        q.add(&quot;23lk&quot;);
        q.add(&quot;22lkjl&quot;);
        q.add(&quot;45ljl&quot;);

        for(String str : q) {
            System.out.println(str);
        }
    }
}

adn output

22lkjl
23lk
45ljl

If this not solution, please explain problem with more details, may be I or anybody else will help you.

huangapple
  • 本文由 发表于 2020年8月19日 01:04:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/63473392.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定