処理に時間がかかる場合は、待っている間に他のことができるよう通知設定しています。
目立たせるため、関数にしました。
import os
# Macのデスクトップ通知
def notification():
os.system("osascript -e 'display notification \"〇〇チェック\nコード実行終了\"'")
notification()
処理に時間がかかる場合は、待っている間に他のことができるよう通知設定しています。
目立たせるため、関数にしました。
import os
# Macのデスクトップ通知
def notification():
os.system("osascript -e 'display notification \"〇〇チェック\nコード実行終了\"'")
notification()
辞書型データからのvalue取得、キーの任意並べ替え(valueがない場合にも対応)、データフレームとの相互変換、CSVファイルへの変換が含まれたコードです。
import pandas as pd
<中略>
df = pd.read_csv(path,header=None,encoding='shift_jis')
df2 = df.drop_duplicates(subset=[0])
# データフレームを辞書型データに変換
dict = {str(x) : str(y) for x,y in zip(df2[0],df2[1])}
# 15項目の辞書型データを作成(valueがない場合はnanを入力)
dict2 = {'馬名':dict.get('馬名','nan'),'稼働':dict.get('稼働','nan'), '性別':dict.get('性別','nan'), '毛色':dict.get('毛色','nan'), '生年月日':dict.get('生年月日','nan'), '調教師':dict.get('調教師','nan'), '馬主':dict.get('馬主','nan'),'募集情報':dict.get('募集情報','nan'),'生産者':dict.get('生産者','nan'), '産地':dict.get('産地','nan'), 'セリ取引価格':dict.get('セリ取引価格','nan'), '獲得賞金':dict.get('獲得賞金','nan'), '通算成績':dict.get('通算成績','nan'), '主な勝鞍': dict.get('主な勝鞍','nan'), '近親馬':dict.get('近親馬','nan')}
# 辞書型データをデータフレームに変換
df3 = pd.json_normalize(dict2)
# df3の行と列を転置してCSVファイルを作成(T属性を使う)
with open(path,mode="w",encoding="cp932", errors="ignore") as f:
df3.T.to_csv(f,header=False)
[macOS Catalina 10.15.7]
普段の開発環境はVScodeですが、簡単なコードはIDLEで実行しています。
コマンドは以下の通りです(pandasの場合)。
/Library/Frameworks/Python.framework/Versions/3.9/bin/python3.9 -m pip install pandas
メモ書きしておきます。
for path in paths:
df = pd.read_csv(path,header=None,encoding='shift_jis')
# 列0の値が重複する場合に最初の行だけ残す
df2 = df.drop_duplicates(subset=[0])
with open(path,mode="w",encoding="cp932", errors="ignore") as f:
df2.to_csv(f,index=False,header=False)
リスト同士を比較して差分を演算するコードの一例です。
千番単位で連番リストを作り、比較したいリストとの差集合を演算します。
# 連番リスト作成
list_num = [[str(x).zfill(5) for x in range(1000*thou +1,1000*thou +1001)] for thou in range(0,11) ]
# 比較リスト作成
list_compare_pre = glob.glob('/*.csv')
list_compare = [path.split('.')[0][-5:] for path in list_compare_pre]
# 欠番リスト作成
list_lack = list(set(list_num[0]) - set(list_compare))
list_lack.sort()
前回の続きです。
for文ではなくリスト内包表記で書くと以下の通りになります。
リストを関数の戻り値にすることもできますが、普通に変数にする方が使い勝手は良さそうです。
# 00001から11000までの千番台ごとのリストを入れ子にしたリストを作成する関数
def list_num():
return [[str(x).zfill(5) for x in range(1000*thou +1,1000*thou +1001)]\
for thou in range(0,11) ]
list_num_flat = [y for x in list_num() for y in x]
print(len(list_num_flat))
--------------------------------------------------
出力
--------------------------------------------------
11000
00001から11000のゼロ埋め数字を1000個ずつまとめたリストの作成コードです。欠番検索の元データに使えます。
リスト内の1つ目のリストは00001から01000のゼロ埋め数字で構成されています。
list_all = list()
for thousand in range(0,11,1):
list_thou = list()
for num in range(1,1001,1):
number = 1000*thousand + num
# 数字を5桁のゼロ埋め数字に変換する
number_5digits = str(number).zfill(5)
list_thou.append(number_5digits)
list_all.append(list_thou)
# リストを平滑化して入れ子をなくす
list_all_flat = [y for x in list_all for y in x]
print(len(list_all_flat))
--------------------------------------------------
出力
--------------------------------------------------
11000
久しぶりにPythonをいじりました。最近は融通の効かないJavaを使いこなすことにやりがいを感じていましたが、Pythonの自由さもいいものです。
globメソッドで得られたCSVファイルのパス一覧から、ファイル内容が条件に合致するパスのリストを作成しようとしたところ、エラーになってしまう問題にぶつかりました。さすがにそこまで柔軟ではないようです。
仕方ないのでパスをprint関数でtxtファイルに追記出力しました。
# 競走馬個別ファイル内の競走馬名が幼名("XXXの2018"など)になっているファイルのパスリストを作成
import glob,os,re,sys
import pandas as pd
print("検索する年度を入力してください")
year = input()
path = f'/horse/{year}'
print(os.listdir(path))
# 数字が含まれているディレクトリ名をリスト化する
pattern = r'\d'
list_dir = [p for p in os.listdir(path) if re.compile(pattern).search(p)]
print(list_dir)
for dir in list_dir:
for path in glob.glob(f'/horse/{year}/{dir}/*.csv'):
df = pd.read_csv(path,header = None,encoding='shift_jis')
# B1セル相当の文字列に数字が含まれている場合、ファイルパスを追記出力する
if re.compile(pattern).search(df.iat[0,1]):
print(df.iat[0,1])
with open('未登録馬path.txt', 'a') as f:
print(path, file = f)
# list.append(path)は不可なのでこのような処理になった
ボタンを押した時のアクションについてコードを書き、完成させました。
とりあえずバージョン0.1が出来上がったので、これから少しずつ機能を増やしていきます。
ガワ(GUI部分)はEclipseのサポートで何とかなりそうですし、アプリ機能を正確かつスムーズにコーディングするスキルを磨いていきたいです。
<途中から>
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("Button1")){
String name = text1.getText();
System.out.println("競走馬名取得 " + name);
Horse.IDSearch(name);
ArrayList<String> nameAndIDCon = Horse.IDSearch(name);
Integer count = nameAndIDCon.size()-1;
StringBuilder result = new StringBuilder();
for (String ele:nameAndIDCon) {
result.append(ele);
}
String resultStr = result.toString();
area.append(resultStr + "\n");
if (count >= 2) {
area.append("\n" + "該当する馬が複数います。番号を入力してください。");
nameAndIDCon.subList(0,1).clear();
area.append("\n" + nameAndIDCon + "\n");
int i = 1;
for (String s : nameAndIDCon) {
area.append(i + " " + s + "\n");
i = i + 1;
}
}
else if (count == 0){
area.append("該当する馬はいません"+ "\n");
}
else {
String name2 = nameAndIDCon.get(0);
String ID = nameAndIDCon.get(1);
area.append(name2 + "のIDは" + ID + "です"+ "\n");
ArrayList<ArrayList<String>> raceList = Horse.raceSearch(nameAndIDCon);
ArrayList<ArrayList<String>> raceListCon = Horse.raceSearch2(raceList);
Horse.toHTML(raceListCon,nameAndIDCon);
// HTMLファイルのパスを取得しJEditorPaneに埋め込む
path = HTMLPath.main();
System.out.println(path);
try {
editorPane.setPage(new File(path).toURI().toURL());
}
catch (IOException e1) {
e1.printStackTrace();
}
}
}
else if (cmd.equals("Button2")){
String text3 = text2.getText();
System.out.println(text3);
int numID = Integer.parseInt(text3);
System.out.println(numID);
String name3 = text1.getText();
System.out.println(name3);
ArrayList<String> nameAndIDCon = Horse.IDSearch(name3);
String ID = nameAndIDCon.get(numID);
ArrayList<String> nameAndIDCon2 = new ArrayList<String>();
nameAndIDCon2.add(name3);
nameAndIDCon2.add(ID);
ArrayList<ArrayList<String>> raceList = Horse.raceSearch(nameAndIDCon2);
ArrayList<ArrayList<String>> raceListCon = Horse.raceSearch2(raceList);
Horse.toHTML(raceListCon,nameAndIDCon2);
path = HTMLPath.main();
System.out.println(path);
try {
editorPane.setPage(new File(path).toURI().toURL());
}
catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
contentPaneにパネルとコンポーネントを配置しました。
コンポーネントを左寄せにする方法で少しだけ手間取ったので記録を残しておきます。
SwingはPythonのtkinterに使用感が似ています。ただデザインタブで配置が視覚的にできる分、こちらの方がやや優勢でしょうか。
使い勝手で申し分のないJavaFXが使えないのはつくづく残念です。
あとはボタンアクションを追記し、標準出力をPAGE_ENDに表示させるなどして一応完了となります。
package horse_search;
<importは略>
public class Main extends JFrame {
private JPanel contentPane;
private JTextField textField;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Main() {
// contentPane設定
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 1500, 750);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
// CENTER設定
JEditorPane editorPane = new JEditorPane();
contentPane.add(editorPane, BorderLayout.CENTER);
editorPane.setContentType("text/html");
try {
editorPane.setPage(new File("シャフリヤール.html").toURI().toURL());
}
catch (IOException e) {
e.printStackTrace();
}
// PAGE_START設定
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
contentPane.add(panel, BorderLayout.PAGE_START);
JLabel label = new JLabel("競走馬名");
JTextField text = new JTextField(20);
JButton btnNewButton = new JButton("検索");
textField = new JTextField(3);
JButton btnNewButton_1 = new JButton("確定");
panel.add(label);
panel.add(text);
panel.add(btnNewButton);
panel.add(textField);
panel.add(btnNewButton_1);
// PAGE_END設定
JPanel panel2 = new JPanel();
panel2.setLayout(new FlowLayout(FlowLayout.LEFT));
contentPane.add(panel2, BorderLayout.PAGE_END);
JTextArea textArea = new JTextArea(15,30);
textArea.setLayout(new FlowLayout(FlowLayout.LEFT));
panel2.add(textArea);