キャッシュとセッションとクッキーについて簡単に
クッキー
- 「誰が」というユーザー情報をブラウザに保存
- 一時的なものと永続的なものが存在
- 無効にできる
セッション
- ユーザーの「行動」をブラウザもしくはサーバーに保存
- クッキーと違い永続的なものは存在しない(ブラウザを閉じるか、サイトから離れると削除される)
- 無効にできない
キャッシュ(ブラウザのキャッシュ)
- 画像やファイルが保存され、サイトへのアクセス速度向上
- キャッシュファイルが保存されるフォルダがローカルに存在
- 永続的(有効期限を設定可能)
Java + Thymeleafでth:eachの繰り返し表示を整理
問題
コントローラーからのデータをテーブル表示で並べてくれとの要件
問題は一部がList型なため、そのサイズ分の行数必要になり、
その他のデータは中身が同じなため、同じデータが繰り返し表示されてなんか嫌だった
やったこと
そこで、前回も大変お世話になった#numbers.sequence
を使って解決
繰り返し表示する必要のない列は最初の行だけ表示するよう、
th:if="${i == 0}"
で制御して、th:rowspan="${list.size()}"
で結合
これで繰り返し表示が必要なものだけ、サイズ分行数が表示され、
それ以外は、大きな一行でまとまったテーブルの完成
<table> <thead> <tr> <th>1</th> <th>2</th> <th>3</th> </tr> </thead> <tbody> <tr th:each="i : ${#numbers.sequence(0, sampleForm.sampleList.size()-1)}"> <td th:if="${i == 0}" th:rowspan="${sampleForm.sampleList.size()}" th:text="1"></td> <td th:if="${i == 0}" th:rowspan="${sampleForm.sampleList.size()}" th:text="2"></td> <td th:text="${sampleForm.sampleList[i]}"></td> </tr> </tbody> </table>
SpringBoot + Thymeleafでチェックボックスを任意の列で表示
環境
Spring Boot 2.7.11
Java 11
目的
コントローラーから取得したリストを基に任意の列で、チェックボックスを横並びにしたい
実装コード
<div class="form-group row"> <details> <summary>LIST1</summary> <table style="margin-left: 60px; width: 90vw"> <tr th:each="i : ${#numbers.sequence(0, list1.size() - 1, 3)}"> <td th:each="value, status : ${list1.subList(i, i + 3 < list1.size() ? i + 3 : list1.size())}" th:style="${list1.size()} >= 3 ? 'width: 30vw;' : (${status.index} % 3 == 0 ? 'width: 15vw;' : 'width: 30vw;')"> <input class="form-check-input" type="checkbox" th:value="${value}"> <label class="form-check-label" th:text="${value}"></label> </td> </tr> </table> </details> </div> <div class="form-group row"> <details> <summary>LIST2</summary> <table style="margin-left: 60px; width: 90vw"> <tr th:each="i : ${#numbers.sequence(0, list2.size() - 1, 3)}"> <td th:each="value, status : ${list2.subList(i, i + 3 < list2.size() ? i + 3 : list2.size())}" th:style="${list2.size()} > 2 ? 'width: 30vw;' : (${status.index} == 0 ? 'width: 15vw;' : 'width: 30vw;')"> <input class="form-check-input" type="checkbox" th:value="${value}"> <label class="form-check-label" th:text="${value}"></label> </td> </tr> </table> </details> </div>
表示画面
説明
上記コードは3列で表示するもの
trタグのeachはコントローラーから受け取ったlist1というリストを3つずつ扱うために、
i : #numbers.sequence(from, to, step)
1のstepを3と指定
Javaでいうfor (int i = 0; i < list1.size() - 1; i+=3)
と同じ
tdタグのeachはJavaの標準メソッドsubList(form, to)
2でlist1を、
要素数が3つずつになるようi+3までeach文を実行する
th:styleの三項演算子は、チェックボックス各々の幅をウィンドウのサイズに応じて、
単純にwidth: 30vw;
で3分割できればよかったのだが、
リストのサイズが2の時だけ1つ目と2つ目のチェックボックスの間が広くなり、
他のグループの項目と2つ目のチェックボックスの位置がずれてしまうため、
一番最初の要素の幅だけ1/6のサイズに指定した
・リストサイズが1の時、幅によって少々ズレることがあったためth:styleの最初の条件を2未満に
注意
時間がなかったために、このような可読性の低いコードをVIEWに書くことになってしまい、
探せばもっと単純で簡単な実装方法があると思います。
- Thymeleafのユーティリティメソッド:Tutorial: Using Thymeleaf (ja)↩
- Java11ドキュメント:List (Java SE 11 & JDK 11 )↩
AOJ ALDS1_3_C 双方向連結リスト (Java11)
最終的な提出コード(AC)
class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); Deque<Integer> list = new ArrayDeque<Integer>(); String str = br.readLine(); int n = Integer.parseInt(str); for (int i = 0; i < n; i++) { String tmp = br.readLine(); if (tmp.equals("deleteFirst")) { list.pop(); } else if (tmp.equals("deleteLast")) { list.removeLast(); } else { String command = tmp.substring(0, tmp.indexOf(" ")); int x = Integer.parseInt(tmp.substring(tmp.indexOf(" ")+1)); if (command.equals("insert")) list.push(x); else if (command.equals("delete")) list.remove((Integer) x); } } Iterator iterator = list.iterator(); int i = list.size(); int j = 0; while (iterator.hasNext()) { if (j != i-1) { System.out.print(iterator.next()); System.out.print(" "); } else { System.out.println(iterator.next()); } j++; } } }
自力で届いた回答
class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); var list = new ArrayList<Integer>(); String str = br.readLine(); int n = Integer.parseInt(str); for (int i = 0; i < n; i++) { String tmp = br.readLine(); if (tmp.equals("deleteFirst")) { list.remove(0); } else if (tmp.equals("deleteLast")) { list.remove(list.size()-1); } else { String command = tmp.substring(0, tmp.indexOf(" ")); int x = Integer.parseInt(tmp.substring(tmp.indexOf(" ")+1)); if (command.equals("insert")) list.add(0, x); else if (command.equals("delete")) list.remove((Integer) x); } } for (int i = 0; i < list.size(); i++) { if (i != list.size()-1) { System.out.print(list.get(i)); System.out.print(" "); } else { System.out.println(list.get(i)); } } } }
- テストケース10でTLEになり通らず
元々は入力をScannerで受け取っていたが、
sc.next()
だと、空白を区切りと判断し文中の x を受け取れておらず
sc.nextLine()
で、一行受け取ってしまえば良かったと思った頃には後者のコードを記述済み
前者と後者で違いは、
x をArrayDeque<>かArrayList<>に入れるか
使用するデータ構造に伴った関数の利用
テストケース10はおそらく、全てのcommandがinsertであり、
ArrayDequeのpush(),addFirst()とArrayListのadd()に計算量の差があるとみる
- SE11のソースを読んでみたが、イマイチ理解に至らず
SQLローダー実行時、マッピング対象外の日付をテーブル(一列目)へ登録
目的:SQLローダーでCSVを取り込む際に、マッピング対象ではない日付をテーブルへ追加したい
ctlファイル(色々省略)
・ ・ FIELDS TERMINSTED BY '.' TRATLING NULLCOLS ( INPUT_DATE CAHR "TO_CHAR(SYSDATE, YYYY/MM/DD)", COL1, COL2, COL3, )
CSV( input )
CO1 | COL2 | COL3 |
---|---|---|
sample1 | sample2 | sample3 |
上記のctlファイルでSQLローダーを実行したら、テーブルの値が下記の通り一列ずれました。
テーブル
INPUT_DATE | COL1 | COL2 | COL3 |
---|---|---|---|
2023/01/01 | sample2 | sample3 |
解決:マッピングに関係のない項目は、マッピング対象の後に定義し直すことにより解決しました。
ctlファイル(after)
・ ・ FIELDS TERMINSTED BY '.' TRATLING NULLCOLS ( COL1, COL2, COL3, INPUT_DATE CAHR "TO_CHAR(SYSDATE, YYYY/MM/DD)", )
テーブル(after)
INPUT_DATE | COL1 | COL2 | COL3 |
---|---|---|---|
2023/01/01 | sample1 | sample2 | sample3 |
ABC249 C - Just K
キーワード
ビット全探索
ビット演算
シフト演算
キーワードについて解説していきます
シフト演算
見やすさ重視でバイナリ表記で出力していますが、下記コードは右シフトの演算です
例:0010 >> 0001 = 00001, 1000 >> 0010 = 0010
演算子の右側にある1が見えなくなるまでずらしていき、
同じ分だけ、左側もずらされる
for i in range(1,4): for j in range(3): print(bin(i>>j)) >>> 0b1 # 0b1 >> 0b0 0b0 # 0b1 >> 0b1 0b0 # 0b1 >> 0b10 0b10 # 0b10 >> 0b0 0b1 # 0b10 >> 0b1 0b0 # 0b10 >> 0b10 0b11 # 0b11 >> 0b0 0b1 # 0b11 >> 0b1 0b0 # 0b11 >> 0b10
ビット演算 ( &のみ )
&演算子は、お互い1の時のみ1を返します
例:0001 & 0001 = 0001, 1010 & 1010 = 1010, 0101 & 1001 = 0001
※ and(論理演算子)で&(ビット演算子)となり別物
print(bin(7&3)) # 0b111 & 0b11 >>> 0b11
ビット全探索
3つのうち、2パターンの合計は2^3(1<<3) = 8通り
2パターンとはバイナリの0と1、つまり選ぶ( 1 )か選ばない( 0 )か
これを使って、N個の文字列から好きな個数を選択するための全通りが行える
for i in range(1<<3): for j in range(3): print(bin(i>>j & 1)) >>> 0b0 0b0 0b0 0b1 0b0 0b0 0b0 0b1 0b0 0b1 0b1 0b0 0b0 0b0 0b1 0b1 0b0 0b1 0b0 0b1 0b1 0b1 0b1 0b1
解答
キーワードに関する説明は省くとして、
アルファベットの配列(a = 0 を起点とする,)に、選択した文字列に含まれる単語をカウントしていく
配列の要素つまりカウント数が==Kとなっている数が一番多い時をansに記憶しておく
N, K = map(int, input().split()) S = [input() for _ in range(N)] ans = 0 for i in range(1<<N): alph = [0]*26 cnt = 0 for j in range(N): if i>>j & 1: for k in S[j]: alph[ord(k)-ord('a')] += 1 for j in range(26): if alph[j] == K: cnt += 1 ans = max(ans, cnt) print(ans)
参考
bit 全探索 - けんちょんの競プロ精進記録
ビット演算 (bit 演算) の使い方を総特集! 〜 マスクビットから bit DP まで 〜 - Qiita
ABC243 C - Collision 2
atcoder.jp
愚直に解こうとすると時間内に処理を終えることができずTLEになるので、
Yをキーとした、
Lの中で一番Xが大きいもの(left_max)、Rの中で一番Xが小さいもの(right_min)のみで、
解けば実行時間の制限にひっかかることなく処理を終えれます
あとは、どんな時にYesとなるか条件を書けば無事ACです
and 以降を忘れると、
X = 1, 2, 3, 4 Y = 1, 1, 1, 1 S = LLRR
こんな時にもYesを出力しちゃうので、忘れないように
解答
N = int(input()) X,Y = [],[] for _ in range(N): x,y = map(int,input().split()) X.append(x) Y.append(y) S = input() left_max, right_min = dict(),dict() for i in range(N): if S[i] == 'R': if Y[i] in right_min: right_min[Y[i]] = min(X[i], right_min[Y[i]]) else: right_min[Y[i]] = X[i] else: if Y[i] in left_max: left_max[Y[i]] = max(X[i], left_max[Y[i]]) else: left_max[Y[i]] = X[i] if S[i] == 'R': if Y[i] in left_max and right_min[Y[i]] < left_max[Y[i]]: print('Yes') exit() else: if Y[i] in right_min and right_min[Y[i]] < left_max[Y[i]]: print('Yes') exit() print('No')