同时按行长度和字母顺序对字符串数组进行排序

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

Sort string array by line length AND alphabetically at once

问题

我已经看到这个问题在其他几种语言中被提问过,并且都有很好的答案。例如:

https://stackoverflow.com/questions/65276619/how-to-sort-a-file-by-line-length-and-then-alphabetically-for-the-second-key

https://stackoverflow.com/questions/4659524/how-to-sort-by-length-of-string-followed-by-alphabetical-order

https://stackoverflow.com/questions/27114162/sort-strings-alphabetically-and-by-length

我无法在 Golang 中解决这个问题 :/
假设我有以下列表:

2 22 2H 2J 2J2 2J3 2J322422 2J322423 2J33 2M 2P 2W 2X

我希望排序后的输出是:

2 22 2H 2J 2M 2P 2W 2X 2J2 2J3 2J33 2J322422 2J322423

我在 Golang 中尝试了一些方法,但就是无法让它正常工作。

// Log
t.Log.Println(values)

// 按字母顺序对值进行排序
sort.Strings(values)

// 按长度对值进行排序
sort.Slice(values, func(i, j int) bool {
    return len(values[i]) < len(values[j])
})

// Log
t.Log.Println(values)
英文:

I have seen this question asked in a few other languages, each with great answers. i.e.

https://stackoverflow.com/questions/65276619/how-to-sort-a-file-by-line-length-and-then-alphabetically-for-the-second-key

https://stackoverflow.com/questions/4659524/how-to-sort-by-length-of-string-followed-by-alphabetical-order

https://stackoverflow.com/questions/27114162/sort-strings-alphabetically-and-by-length

I can't figure it out in Golang :/
Say I have this list:

2 22 2H 2J 2J2 2J3 2J322422 2J322423 2J33 2M 2P 2W 2X

I want the sorted output to be:

2 22 2H 2J 2M 2P 2W 2X 2J2 2J3 2J33 2J322422 2J322423

I have tried a few things in Golang, but just can't get it working.

// Log
t.Log.Println(values)

// Sort values alphabetically
sort.Strings(values)

// Sort values by length
sort.Slice(values, func(i, j int) bool {
	return len(values[i]) &lt; len(values[j])
})

// Log
t.Log.Println(values)

答案1

得分: 6

如果你进行两次排序,第二次排序将不考虑第一次排序的规则。

你必须进行一次排序,排序规则必须包括你想要排序的所有属性。

所以首先你想按长度排序。如果两个元素的长度相同,再按自然顺序排序。你可以通过在less()函数中首先检查长度来实现这一点。如果它们不相等,那么长度决定结果的顺序。如果它们相等,就按自然顺序排序。

list := strings.Split("2 22 2H 2J 2J2 2J3 2J322422 2J322423 2J33 2M 2P 2W 2X", " ")
fmt.Println(list)

sort.Slice(list, func(i, j int) bool {
	l1, l2 := len(list[i]), len(list[j])
	if l1 != l2 {
		return l1 < l2
	}
	return list[i] < list[j]
})
fmt.Println(list)

这将输出以下结果(在Go Playground上尝试):

[2 22 2H 2J 2J2 2J3 2J322422 2J322423 2J33 2M 2P 2W 2X]
[2 22 2H 2J 2M 2P 2W 2X 2J2 2J3 2J33 2J322422 2J322423]

你可以扩展这个逻辑来按任意数量的属性(或规则)排序。你首先检查优先级较高的规则,如果它们定义了顺序的差异,你返回它们指定的顺序(即i<sup>th</sup>元素是否小于j<sup>th</sup>元素)。如果它们不能区分所讨论的元素的位置,你继续使用优先级较低的规则。

英文:

If you sort twice, the second sorting will not take the rules of the first sorting into account.

You must sort once, and the sorting rule(s) must include all properties you want to sort by.

So primarily you want to sort by length. And if 2 elements have the same length, then by natural order. You can achieve this by first checking the lengths in the less() function. If they are not equal, then the order by length is what decides the result. If they are equal, you resort to natural order.

list := strings.Split(&quot;2 22 2H 2J 2J2 2J3 2J322422 2J322423 2J33 2M 2P 2W 2X&quot;, &quot; &quot;)
fmt.Println(list)

sort.Slice(list, func(i, j int) bool {
	l1, l2 := len(list[i]), len(list[j])
	if l1 != l2 {
		return l1 &lt; l2
	}
	return list[i] &lt; list[j]
})
fmt.Println(list)

This will output (try it on the Go Playground):

[2 22 2H 2J 2J2 2J3 2J322422 2J322423 2J33 2M 2P 2W 2X]
[2 22 2H 2J 2M 2P 2W 2X 2J2 2J3 2J33 2J322422 2J322423]

You can extend this logic to sort by any number of properties (or rules). You check the higher priority rules first, and if they define difference in order, you return the order designated by them (the information whether the i<sup>th</sup> element is less than the j<sup>th</sup>). If they don't differentiate the positions of the elements in question, you proceed with lower priority rules.

答案2

得分: 2

你需要一个比较器函数,根据你定义的排序规则进行正确比较。

要对字符串切片进行排序,首先按长度排序,然后按字母顺序排序,可以使用以下代码:

strs := []string{
  "Zulu"    , "Yankee" , "X-Ray"  , "Whiskey" , "Victor" ,
  "Ulysses" , "Tango"  , "Sierra" , "Romeo"   , "Quebec" ,
  "Poppa"   ,"Oscar"   , "Nancy"  , "Mike"    , "Lima"   ,
  "Kilo"    , "Juliet" , "India"  , "Hotel"   , "Golf"   ,
  "Foxtrot" , "Echo"   , "Delta"  , "Charlie" , "Bravo"  ,
  "Alpha"   ,
}

byLengthThenAlphabetically := func(i int, j int) bool {
  x := strs[i]
  y := strs[j]
  deltaLength := len(x) - len(y)

  return deltaLength < 0 || (deltaLength == 0 && x < y)
}

sort.Slice(strs, byLengthThenAlphabetically )

在Go Playground中尝试一下:https://play.golang.org/p/nL2bTDlWM49

英文:

You need a comparator function that compares properly according to the collation rules that you have defined.

To sort a slice of strings, first by length, and then alphabetically, something like this should do you:

strs := []string{
  &quot;Zulu&quot;    , &quot;Yankee&quot; , &quot;X-Ray&quot;  , &quot;Whiskey&quot; , &quot;Victor&quot; ,
  &quot;Ulysses&quot; , &quot;Tango&quot;  , &quot;Sierra&quot; , &quot;Romeo&quot;   , &quot;Quebec&quot; ,
  &quot;Poppa&quot;   ,&quot;Oscar&quot;   , &quot;Nancy&quot;  , &quot;Mike&quot;    , &quot;Lima&quot;   ,
  &quot;Kilo&quot;    , &quot;Juliet&quot; , &quot;India&quot;  , &quot;Hotel&quot;   , &quot;Golf&quot;   ,
  &quot;Foxtrot&quot; , &quot;Echo&quot;   , &quot;Delta&quot;  , &quot;Charlie&quot; , &quot;Bravo&quot;  ,
  &quot;Alpha&quot;   ,
  }

  byLengthThenAlphabetically := func(i int, j int) bool {
    x := strs[i]
	y := strs[j]
    deltaLength := len(x) - len(y)

    return deltaLength &lt; 0 || (deltaLength == 0 &amp;&amp; x &lt; y)
  }
  
  sort.Slice(strs, byLengthThenAlphabetically )

Try it in the Go Playground at https://play.golang.org/p/nL2bTDlWM49

huangapple
  • 本文由 发表于 2021年11月5日 05:45:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/69846196.html
匿名

发表评论

匿名网友

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

确定