2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【jQuery】要素内の文字列に含まれる数値でリストをソートする【js】

Last updated at Posted at 2020-02-22

##経緯
やんごとなき理由でhtml側をいじれなかったため、
jsでどうにかこうにか入れ替える必要がありました。
以下奮闘記です。

もっといい書き方があればコメント下さい。泣いて喜びます。

##今回の要件

  • お店の開店時間が早い順にソートしたい
  • 開店時間が同じ場合でも、閉店時間による並べ替えはしない
  • 時間は24時間表記、30分刻みとする
  • 営業時間は必ずHH:mm ~ HH:mmのフォーマットで表記される
  • すべての店の営業時間は10:00 ~ 5:00の範囲内に収まる(5時オープンの店はない)

##デモ
デモはこちら。
開店時間を変更しても、並び替わってくれます。

##HTML

hoge.html
<ul class="shop_lists">
  <li>
    <div class="shop">HOGE食堂</div>
    <div class="time">12:00 ~ 18:00</div>
  </li>
  <li>
    <div class="shop">FUGA KITCHEN</div>
    <div class="time">10:00 ~ 20:00</div>
  </li>
  <li>
    <div class="shop">BAR NULL</div>
    <div class="time">1:00 ~ 4:00</div>
  </li>
</ul>

##javascript

hoge.js
$('.shop_lists').html(
	$('.shop_lists > li').sort(function(a,b){
		var str1 = $(a).find('.time').html();
		var str2 = $(b).find('.time').html();
		var num1 = str1.substr( 0, 4 ).split(':');
		var num2 = str2.substr( 0, 4 ).split(':');

			if(num1[0] < 5){
				num1[0] = Number(num1[0]) + 24;
				num1[0] += Number(num1[1]) / 100; 
			}
			if(num2[0] < 5){
				num2[0] = Number(num2[0]) + 24;
				num2[0] += Number(num2[1]) / 100; 
			}

		return num1[0] - num2[0];
}));

##生意気にも解説
###リストの入れ替え

$('.shop_lists > li').sort(function(a,b){

sortメソッドで数値を複数回比較、比較した値を基に、
liタグの並べ替えを行います。
比較方法については次から。

###基準となる数値を含む文字列を抽出

var str1 = $(a).find('.time').html();
var str2 = $(b).find('.time').html();

aそれぞれに、リストがセットされて行くので、
その中から、timeクラスを持つブロックを指定し、
htmlメソッドで中身(今回だと12:00 ~ 18:00)を抽出します。

ただ、これだと~と閉店時間が含まれてしまうため、
次に開店時間のみ抽出していきます。

###数値の抽出と比較の下準備

var num1 = str1.substr( 0, 4 ).split(':');

まず、セットされた文字列から先頭の4文字を指定substr( 0, 4 )します。
12:00 ~ 18:00だと12:0になりますね。

※今回は時間が30分刻みで、1分単位での比較はしなくて良いので切り捨てています。

次に、文字列をを基準に、分割し配列化します。
上の例だと、num1 = ['12', '0']となります。

では、この配列の値を基準に比較する処理に入ります。

###比較方法

return num1[0] - num2[0];

順番が前後しますが、結論から言うと、
配列の最初の値num[0]を比較します。

この比較結果を基にリストを並べ替えていくわけですね。(完全に理解)

####問題点
ただこれだけだと、以下の問題が発生してしまいます。

  • リスト分単位での比較が出来ない
  • 0時以降オープンのお店が、10時オープンのお店より先に表示されてしまう

そのため今回は、

  • 分単位部分のnum[1]を少数点以下の数値に変換し、num[0]に加算。
  • 0時〜5時の場合は、num[0]に24を足す(24時〜28時に変換)

これらの処理を挟むことにしました。

###問題点を解決する処理

if(num1[0] < 6){
		num1[0] = Number(num1[0]) + 24;
		num1[0] += Number(num1[1]) / 100; 
			//結果(1時半オープンの場合): num1[0] = 25.3
	}

この部分ですね。

暗黙の型変換でそのまま24を足したり100で割ることもできるみたいですが、
丁寧に書きましょうということで、Numberオブジェクトで型変換の後に計算。

これで、先程の問題は解決します。

あとは先程の比較式に値が渡るので、比較の後、並べ替え完了です!!!

##思うところ
aとbで同じ処理してるので、うまいことまとめられないかなーというのが正直な所。

ループ回したりしてカッチョイイコードを書きたいものの、
正直わかりやすいし2回くらいならいっか()という惰性です。

あと、時間フォーマットの変更に強くないので、
その場しのぎ感は否めないかと。

自分のコードを呪う未来が見えるような、見えないような....。

間違い等あれば、ご指摘下さい。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?