以 sort 進行多重條件排序

YiChe Liu
5 min readJun 30, 2022

--

我們都知道可以使用 sort() 來排序,除了單純排序數字,也可以搭配 localeCompare 以不同語系排序文字。當然,也可以用 || 來做多重條件排序。不過工作上出現一個小複雜的問題,想出解法時覺得不筆記起來有點可惜。

單一條件排序

先來看一下 sort 最基本的用法:

const array = [1, 3, 8, 6, 4];
array.sort();
// array 會變成 [1, 3, 4, 6, 8]

單純使用 sort() 會以小到大排序,不過他是以 Unicode 編碼的方式去比,並不是以數字大小排序,也就是:

const array = [1, 100, 98, 654, 45];
array.sort();
// array 會變成 [1, 100, 45, 654, 98]

似乎跟真正需要的不一樣對吧?所以要把 sort() 改為:

const array = [1, 100, 98, 654, 45];
array.sort((x,y)=>x-y);
// array 會變成 [1, 45, 98, 100, 654]

x 和 y 是參數,可以自己命名。背後的原理是把 x y 拿出來比較,回傳索引值:

function compare(x, y) {
if (在某排序標準下 x 小於 y) {
return -1;
}
if (在某排序標準下 x 大於 y) {
return 1;
}
// x 必須等於 y
return 0;
}

sort 也可以用陣列裡的物件屬性來比較,舉例來說:

const array = [
{title:'pineapple', price: 100},
{title:'banana', price: 35}
];
array.sort((x,y)=>x.price-y.price);
// array 會變成 [
{title: 'banana', price: 35},
{title: 'pineapple', price: 100}
]

比較文字時因為會牽扯到語系問題,舉例來說英文要以英文字母來排、中文要以筆畫來排等等,可以使用 localeCompare 來解決這個問題:

// 英文const array = ['pineapple', 'banana'];
array.sort((x,y)=>x.localeCompare(y));
// array 會變成 ['banana', 'pineapple']
// 中文
const array = ['鳳梨', '香蕉'];
array.sort((x,y)=>x.localeCompare(y, 'zh-Hant'));
// array 會變成 ['香蕉', '鳳梨']

多重條件排序

如果要比較陣列裡的物件,先以物件的價格做排序,價格一樣時以標題做排序,該怎麼處理呢?只要搭配 || 就可以了。

const array = [
{title:'pineapple', price: 100},
{title:'banana', price: 35},
{title:'apple', price: 35}
];
array.sort((x,y)=>x.price-y.price || x.title.localeCompare(y.title));
// array 會變成 [
{title: 'apple', price: 35},
{title: 'banana', price: 35},
{title: 'pineapple', price: 100}
]

問題

講了這麼多,終於可以講我遇到的問題。這個問題的需求是:

  1. 取得 API 後,需要先以攤位編號(booth_number)排序
  2. 若攤位編號相同,以標題(title)排序
  3. 標題可能中英文混雜,以第一個字的英文字母、中文筆畫順序排序
  4. 攤位編號後台可能沒有輸內容,也就是抓到的資料為空值 null 。因此若無攤位邊號,要放在最後面,以標題第一個字的英文字母、中文筆畫順序排序

直覺上我就想,

  1. 先把有攤位編號資料的東西抓出來變成一個陣列 boothNotNull、沒有的變成另一個陣列 boothNull。
  2. 把 boothNull 裡先抽出第一個字母,把他們詳細區分成中文陣列、英文陣列,分開排序,再把排序後的內容放回一起。
  3. boothNotNull 則是先比較攤位編號,然後…

然後就卡關了。雖然我知道可以用 || 來做多重判斷,但裡頭還要額外判斷中文、英文,這些又要用不同語系排序…

[ 當時卡關的 code example ]

解決

後來轉念一想,我不如:

  1. 先不管有沒有攤位編號,把標題中英文排序搞定。
  2. 取得所有資料的中英文排序後,用 indexOf 找到他在正確排序陣列中的位置,在每筆物件中新增一個 titleKey 屬性存放。
  3. 接著開始區分攤位編號,有資料的放一組,沒資料的放一組。
  4. 有資料的以編號排序,編號相同時以 titleKey 比較。
  5. 無資料時以 titleKey 比較。

[ 最後解出來的 code example ]

以上就是這次的解決方案!

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

YiChe Liu
YiChe Liu

Written by YiChe Liu

小菜鳥前端 / 親手打過的筆記才是自己的

No responses yet

Write a response