質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

4回答

1170閲覧

Pythonでのシフト作成における入れ替え

yoshipiman

総合スコア6

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/01/14 14:18

編集2020/01/15 07:19

前提・実現したいこと

現在、シフト作成のプログラムを作成しています。
【手順】
・日にち、時間帯ごとにシフト希望をリスト化
・それを能力値順にソート
・ソートされたリストから必要人数分取る。(その際取られなかった人のリストを作っておく)
・各シフトに社員が最低1人いない場合、その日にち、時間帯で入れなかった社員をランダムで選んで、入っている人のランダムで入れ替える
・3連勤している人がいた場合、3連勤の真ん中の日にちをその日にち、時間帯で入れなかった人のランダムと入れ替える

このような手順なのですが、最後の2つが途中まででつまずいています。

該当のソースコード

Python

1#従業員=["能力値","シフト希望時間","役職","休む度合い","対応度合い","名前"] 2#役職=["社員","アルバイト"] 3#役職=[0,1] 4#シフト希望時間=[11:00-17:00,17:00-22:00,11:00-22:00,"希望無し"] 5#シフト希望時間=[0,1,2,9] 6 7#aは社員 8a=[5,[2,9,2,2,2],0,1,3,"a"] 9#bは社員 10b=[3,[2,2,2,9,2],0,1,3,"b"] 11#cは主婦 12c=[3,[0,0,0,0,9],1,2,1,"c"] 13#dはフリーター 14d=[4,[2,2,2,9,1],1,2,2,"d"] 15#eは大学生(夕方) 16e=[1,[1,1,9,1,1],1,1,3,"e"] 17#fは大学生(朝) 18f=[2,[9,2,9,2,0],1,1,2,"f"] 19 20member=[a,b,c,d,e,f] 21 22shift = [] 23gozen = [] 24gogo = [] 25 26for i in range(len(member[1][1])): 27 for j in member: 28 if j[1][i] == 0: 29 gozen.append(j) 30 elif j[1][i] == 1: 31 gogo.append(j) 32 elif j[1][i] == 2: 33 gozen.append(j) 34 gogo.append(j) 35 shift.append([gozen, gogo]) 36 gozen = [] 37 gogo = [] 38 39print(shift[0][0]) #1日目の午前の希望 40print(shift[0][1]) #1日目の午後の希望  41print(shift[1][0]) #2日目の午前の希望 42print(shift[1][1]) #2日目の午後の希望 43print(shift[2][0]) #3日目の午前の希望 44print(shift[2][1]) #3日目の午後の希望 45print(shift[3][0]) #4日目の午前の希望 46print(shift[3][1]) #4日目の午後の希望 47print(shift[4][0]) #5日目の午前の希望 48print(shift[4][1]) #5日目の午後の希望 49print(".............................................") 50 51 52#必要人数 53#1日目=[午前の必要人数,午後の必要人数] 54d1=[3,3] 55d2=[2,3] 56d3=[3,2] 57d4=[2,2] 58d5=[2,3] 59 60date=[d1,d2,d3,d4,d5] 61 62 63for day in range(len(shift)): #昇順のソート(能力値の低い順) 64 for am_pm in range(len(shift[day])): 65 shift[day][am_pm].sort() 66 print (shift[day][am_pm]) 67 68print(".............................................") 69 70 71p=[] 72q=[] 73r=[] 74for day in range(len(shift)): #必要人数分取って入れなかった人を別のリストに入れる 75 for am_pm in range(len(shift[day])): 76 for i in range(len(shift[day][am_pm])-date[day][am_pm]): 77 p.append(shift[day][am_pm][i]) 78 shift[day][am_pm].remove(shift[day][am_pm][i]) 79 print (shift[day][am_pm]) 80 q.extend([p]) 81 p=[] 82 r.extend([q]) 83 q=[] 84print (r) 85print(".............................................") 86 87 88x=[]                             #3連勤チェックは時間帯に関係なく日ごとなので、日ごとの午前、午後を一つにまとめる作業 89y=[] 90for day in range(len(shift)): 91 for am_pm in range(len(shift[day])): 92 for i in range(len(shift[day][am_pm])): 93 x.append(shift[day][am_pm][i][5]) 94 y.extend([x]) 95 x = [] 96 97for i in range(len(y)): 98 y[i] = list(set(y[i])) 99 100print(y) 101print(".............................................") 102 103 104for i in range(3):               #3連勤している人の入れ替えのプログラム。途中の入れ替えからが困っています。 105 for j in range(len(y[i])): 106 if y[i+1][j] in y[i]: 107 if y[i+1][j] in y[i+2]: 108 if shift[i+1][j] in shift[i+1]: 109 shift[i+1].append 110 111 112 113for day in range(len(shift)):         #社員が各日にち、時間帯に最低1人はいるかのチェック。いなかった時の入れ替えのプログラムで困っています。 114 for am_pm in range(len(shift[day])): 115 person_list = [] 116 for i in shift[day][am_pm]: 117 person_list.append(i[2]) 118 if 0 in person_list: 119 print('社員います') 120 else: 121 print('社員いません') 122

発生している問題・エラーメッセージ

・各シフトに社員が最低1人いない場合、その日にち、時間帯で入れなかった社員をランダムで選んで、入っている人のランダムで入れ替える ・3連勤している人がいた場合、3連勤の真ん中の日にちをその日にち、時間帯で入れなかった人のランダムと入れ替える この2つのプログラムの「各シフトに社員が最低1人いない場合」、「3連勤している人がいた場合」まではできたのですが「その日にち、時間帯で入れなかった社員をランダムで選んで、入っている人のランダムで入れ替える」と「3連勤の真ん中の日にちをその日にち、時間帯で入れなかった人のランダムと入れ替える」のプログラムがわからないです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lhankor_Mhy

2020/01/15 04:49 編集

「各シフトに社員が最低1人いない場合、その日にち、時間帯で入れなかった社員をランダムで選んで、入っている人のランダムで入れ替える」とのことですが、ここまで決まっているならコードになりませんか? どの部分がわからないのでしょうか? たとえば、「各シフトに社員が最低1人いない場合」がコードにできない、などと具体的にわからない部分を記載した方が回答がつくかもしれません。 何ができていて、何ができていないのか(何がわかっていて、何がわからないのか)を書きましょう https://teratail.com/help/question-tips#questionTips3-5-2
guest

回答4

0

Python

1#従業員=["能力値","シフト希望時間","役職","休む度合い","対応度合い","名前"] 2#役職=["社員","アルバイト"] 3#役職=[0,1] 4#シフト希望時間=[11:00-17:00,17:00-22:00,11:00-22:00,"希望無し"] 5#シフト希望時間=[0,1,2,9] 6 7#aは社員 8a=[5,[2,9,2,2,2],0,1,3,"a"] 9#bは社員 10b=[3,[2,2,2,9,2],0,1,3,"b"] 11#cは主婦 12c=[3,[0,0,0,0,9],1,3,1,"c"] 13#dはフリーター 14d=[4,[2,2,2,9,1],1,2,2,"d"] 15#eは大学生(夕方) 16e=[1,[1,1,9,1,1],1,1,3,"e"] 17#fは大学生(朝) 18f=[2,[9,2,9,2,0],1,3,2,"f"] 19 20member=[a,b,c,d,e,f] 21 22shift = [] 23gozen = [] 24gogo = [] 25 26#各日各時間帯ごとにシフト希望のリストを作る 27for i in range(len(member[1][1])): 28 for j in member: 29 if j[1][i] == 0: 30 gozen.append(j) 31 elif j[1][i] == 1: 32 gogo.append(j) 33 elif j[1][i] == 2: 34 gozen.append(j) 35 gogo.append(j) 36 shift.append([gozen, gogo]) 37 gozen = [] 38 gogo = [] 39 40print(shift[0][0]) #1日目の午前の希望 41print(shift[0][1]) #1日目の午後の希望  42print(shift[1][0]) #2日目の午前の希望 43print(shift[1][1]) #2日目の午後の希望 44print(shift[2][0]) #3日目の午前の希望 45print(shift[2][1]) #3日目の午後の希望 46print(shift[3][0]) #4日目の午前の希望 47print(shift[3][1]) #4日目の午後の希望 48print(shift[4][0]) #5日目の午前の希望 49print(shift[4][1]) #5日目の午後の希望 50print(".............................................") 51 52 53#必要人数 54#1日目=[午前の必要人数,午後の必要人数] 55d1=[3,3] 56d2=[2,3] 57d3=[3,2] 58d4=[2,2] 59d5=[2,3] 60 61date=[d1,d2,d3,d4,d5] 62 63 64for day in range(len(shift)): #昇順のソート(能力値の低い順) 65 for am_pm in range(len(shift[day])): 66 shift[day][am_pm].sort() 67 print (shift[day][am_pm]) 68 69print(".............................................") 70 71 72p=[] 73q=[] 74yasumi=[] 75for day in range(len(shift)): #必要人数分取って入れなかった人を別のリストに入れる 76 for am_pm in range(len(shift[day])): 77 for i in range(len(shift[day][am_pm])-date[day][am_pm]): 78 p.append(shift[day][am_pm][i]) 79 shift[day][am_pm].remove(shift[day][am_pm][i]) 80 print (shift[day][am_pm]) 81 q.extend([p]) 82 p=[] 83 yasumi.extend([q]) 84 q=[]

投稿2020/01/20 06:21

yoshipiman

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Python

1#従業員=["能力値","シフト希望時間","役職","休む度合い","対応度合い","名前"] 2#役職=["社員","アルバイト"] 3#役職=[0,1] 4#シフト希望時間=[11:00-17:00,17:00-22:00,11:00-22:00,"希望無し"] 5#シフト希望時間=[0,1,2,9] 6 7#aは社員 8a=[5,[2,9,2,2,2],0,1,3,"a"] 9#bは社員 10b=[3,[2,2,2,9,2],0,1,3,"b"] 11#cは主婦 12c=[3,[0,0,0,0,9],1,3,1,"c"] 13#dはフリーター 14d=[4,[2,2,2,9,1],1,2,2,"d"] 15#eは大学生(夕方) 16e=[1,[1,1,9,1,1],1,1,3,"e"] 17#fは大学生(朝) 18f=[2,[9,2,9,2,0],1,3,2,"f"] 19 20member=[a,b,c,d,e,f] 21 22shift = [] 23gozen = [] 24gogo = [] 25 26#各日各時間帯ごとにシフト希望のリストを作る 27for i in range(len(member[1][1])): 28 for j in member: 29 if j[1][i] == 0: 30 gozen.append(j) 31 elif j[1][i] == 1: 32 gogo.append(j) 33 elif j[1][i] == 2: 34 gozen.append(j) 35 gogo.append(j) 36 shift.append([gozen, gogo]) 37 gozen = [] 38 gogo = [] 39 40print(shift[0][0]) #1日目の午前の希望 41print(shift[0][1]) #1日目の午後の希望  42print(shift[1][0]) #2日目の午前の希望 43print(shift[1][1]) #2日目の午後の希望 44print(shift[2][0]) #3日目の午前の希望 45print(shift[2][1]) #3日目の午後の希望 46print(shift[3][0]) #4日目の午前の希望 47print(shift[3][1]) #4日目の午後の希望 48print(shift[4][0]) #5日目の午前の希望 49print(shift[4][1]) #5日目の午後の希望 50print(".............................................") 51 52 53#必要人数 54#1日目=[午前の必要人数,午後の必要人数] 55d1=[3,3] 56d2=[2,3] 57d3=[3,2] 58d4=[2,2] 59d5=[2,3] 60 61date=[d1,d2,d3,d4,d5] 62 63 64for day in range(len(shift)): #昇順のソート(能力値の低い順) 65 for am_pm in range(len(shift[day])): 66 shift[day][am_pm].sort() 67 print (shift[day][am_pm]) 68 69print(".............................................") 70 71 72p=[] 73q=[] 74yasumi=[] 75for day in range(len(shift)): #必要人数分取って入れなかった人を別のリストに入れる 76 for am_pm in range(len(shift[day])): 77 for i in range(len(shift[day][am_pm])-date[day][am_pm]): 78 p.append(shift[day][am_pm][i]) 79 shift[day][am_pm].remove(shift[day][am_pm][i]) 80 print (shift[day][am_pm]) 81 q.extend([p]) 82 p=[] 83 yasumi.extend([q]) 84 q=[]

投稿2020/01/20 06:11

yoshipiman

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Python

1for day in range(len(shift)-2): #3連勤禁止 2 for am_pm in range(len(shift[day])): 3 for i in range(len(shift[day][am_pm])): 4 if shift[day][am_pm][i] in shift[day+1][am_pm]: 5 if shift[day][am_pm][i] in shift[day+2][am_pm]: 6 print("3連勤してる") 7 shift[day][am_pm].remove(shift[day][am_pm][i]) 8 shift[day][am_pm].append(random.choice(yasumi[day][am_pm])) 9 print(shift[day][am_pm]) 10 else: 11 print("3連勤してない") 12 else: 13 print("3連勤してない")

投稿2020/01/17 06:08

yoshipiman

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

「その日にち、時間帯で入れなかった社員」は、たとえば、filter(lambda x: x[2] == 0 and ( x[1][0]==0 or x[1][0]==2 ), member)とすると、1日目の午前に入れなかった社員です。

「ランダムで選んで」はrandom.choiceを使うといいでしょう。
https://docs.python.org/ja/3/library/random.html#random.choice

「入れ替え」については、そのまま代入すれば問題ないかと思います。

「時間帯で入れなかった人」については、前述同様filter(lambda x: ( x[1][0]==0 or x[1][0]==2 ) and x[5] != y[i][j], member)のようにして取得できると思います。

社員がいませんと出た後からを具体的にコードでお願い

仰せのままに。

python

1for day in range(len(shift)):#社員が各日にち、時間帯に最低1人はいるかのチェック。いなかった時の入れ替えのプログラムで困っています。 2 for am_pm in range(len(shift[day])): 3 person_list = [] 4 for i in shift[day][am_pm]: 5 person_list.append(i[2]) 6 if 0 in person_list: 7 print('社員います', day, am_pm) 8 else: 9 print('社員いません', day, am_pm) 10 print( 'その日にち、時間帯で入れなかった社員', *filter( lambda x: x[2] == 0 and ( x[1][day]==am_pm or x[1][day]==2 ), member) ) 11 print( 'ランダム', random.choice( [*filter( lambda x: x[2] == 0 and ( x[1][day]==am_pm or x[1][day]==2 ), member)] ) ) 12 print( 'その日にち、時間帯のシフト', shift[day][am_pm] ) 13 print( 'ランダム', shift[day][am_pm][random.randint( 0, len(shift[day][am_pm]) - 1)] ) 14 shift[day][am_pm][random.randint( 0, len(shift[day][am_pm]) - 1)] = random.choice( [*filter( lambda x: x[2] == 0 and ( x[1][day]==am_pm or x[1][day]==2 ), member)] ) 15 print( '入れ替え後の、その日にち、時間帯のシフト', shift[day][am_pm] )

途中からでなくても大丈夫なのでコードを教えて

(これはいわゆる丸投げ質問なのでは……)

python

1def swapStraightDayWorker( member, shift, lastOfStraightDay, straightDayWorker): 2 """ 3 シフトは破壊的に入れ替えます。 4 5 lastOfStraightDay : int 6 3連勤の最後の日 7 straightDayWorker : list 8 3連勤した人 9 """ 10 middleDay = lastOfStraightDay - 1 11 middleDayShift = shift[ middleDay ] 12 #print('入れ替え前シフト', middleDayShift) 13 for hourly, hourlyShift in enumerate(middleDayShift): 14 chosenWorker = random.choice( [ x for x in member if ( x[ 1 ][ middleDay ] == hourly or x[ 1 ][ middleDay ] == 2 ) and x not in hourlyShift ] ) 15 if straightDayWorker in hourlyShift: 16 i = hourlyShift.index( straightDayWorker ) 17 hourlyShift[i] = chosenWorker 18 #print('入れ替え後シフト', middleDayShift)

何度もすみません。これが最後の悩んでいることなのでよろしくお願いします。

個人的には、こういうのは、別質問を立ち上げた方がいいかと思います。


コメントに書いた通り、random.shuffleした後に、keyを指定してmember[i][0]の「能力値」だけでソートをしています。

python

1for day in range(len(shift)): #昇順のソート(能力値の低い順) 2 for am_pm in range(len(shift[day])): 3 random.shuffle(shift[day][am_pm]) 4 shift[day][am_pm].sort(key=lambda x:x[0])

投稿2020/01/15 07:52

編集2020/01/21 07:43
Lhankor_Mhy

総合スコア36115

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yoshipiman

2020/01/15 08:23

ありがとうございます。具体的にコードでお願いできますでしょうか。
Lhankor_Mhy

2020/01/15 08:25

どの部分についてですか?
yoshipiman

2020/01/16 05:59

社員がいませんと出た後からと3連勤の従業員が出た後のプログラムです。
Lhankor_Mhy

2020/01/16 09:01

「3連勤の従業員が出た後のプログラム」とことですが、当方の環境では、ご提示のコードはエラーが出て動作しませんでした。まず、「3連勤の従業員を出す」プログラムをご提示いただけますか?
yoshipiman

2020/01/16 11:25

ありがとうございます。社員がいませんと出た後からと3連勤の従業員が出た後のプログラムを自分でも考えていたのですが、前者の方は一応できました。解決方法のところにコード貼りましたので確認お願いします。 今貼っていただいたコードですがここに出てくるxは何を表しているでしょうか? 3連勤の方ですが、3連勤のチェックの仕方は「1日目、2日目、3日目を比較して3連勤している人がいたら真ん中の2日目を入れ替える」これを1日ずつずらして比較しようと考えているのですが、苦戦していて、for文の途中で止まっています。途中からでなくても大丈夫なのでコードを教えていただきたいです。
Lhankor_Mhy

2020/01/17 00:58

> 解決方法のところにコード貼りましたので確認お願いします。 そのコードは質問文にはなさそうでした。 ところで、「確認」とはなんのことですか? > 今貼っていただいたコードですがここに出てくるxは何を表しているでしょうか? filer関数の引数となっているラムダ式の仮引数で、実引数は`member`変数です。 > for文の途中で止まっています。 いえ、最初のfor文でエラーになっていますよ。 いずれにせよ、「3連勤している人がいた場合」まではできているとのことですから、その結果が出力されるコードをご提示いただけますか?
yoshipiman

2020/01/17 06:08

>そのコードは質問文にはなさそうでした。ところで、「確認」とはなんのことですか? 社員がいなかった場合の方のプログラムが自分でもできたので見ていただきたく送りました。 >filer関数の引数となっているラムダ式の仮引数で、実引数は`member`変数です。 filterとlamdaを知らなかったので勉強になりました。ありがとうございます。 >いえ、最初のfor文でエラーになっていますよ。いずれにせよ、「3連勤している人がいた場合」まではできているとのことですから、その結果が出力されるコードをご提示いただけますか? 解決方法のところに新たにコードを貼りました。一応3連勤の方のプログラムも自分で組むことができたのですが、結果を出すと3連勤してしまっているところがありました。どこを修正すれば良いでしょうか。 前回、3連勤の方、丸投げ質問になってしまい申し訳ありません。今回貼った3連勤の方のプログラムに関して上記のことで悩んでいるのでよろしくお願いします
Lhankor_Mhy

2020/01/17 08:17 編集

> 3連勤してしまっているところがありました。 これは解消が難しいと思います。 たとえば、 1 _bcd_ 2 ab_d_ 3 a_c_e 4 a_c_e のようなシフトがあったとして、 3日目のaの3連勤中日を交換するとなると、bかdしかないわけですが、 1 _bcd_ 2 ab_d_ 3 _bc_e 4 a_c_e どちらと交換しても別の人の新たな3連勤を生み、しかもこのループの中では発見されません。 もちろん、シフト交換した時にループを初めから開始するなら発見できるわけですが、そこでも新たな3連勤を生むかもしれません。 1 _bcd_ 2 a_cd_ 3 _bc_e 4 a_c_e 「ランダムにシフト交換を繰り返していけばいつかは解消するはず」と思うかもしれませんが、 1 _bcd_ 2 a__de 3 _bc_e 4 a_c_e このケースでは、誰かが3連勤になってしまうため、いわゆる「無限ループ」という終了しないプログラムになってしまいます。 一般にこのようなスケジューリング問題はNP困難(多項式時間に解決する一般解が存在しない)と言われています。 正直、私の頭ではついていけない部分が多いです。 https://www.nurse-scheduling-software.com/tutorial/newpage3.htm https://qiita.com/SaitoTsutomu/items/a33aba1a95828eb6bd3f ぜひ頑張ってみてください。
yoshipiman

2020/01/17 08:40

そうですよね。社員が最低1人というのも守らないといけないとなると3連勤を防ぐのは難しいと思いました。 最後に質問なのですが、シフトの決め方は各日各時間帯のシフト希望を従業員の能力値順にソートしてそこから必要人数を取るという方法なのですが、ソートした中から前から順番に取るので、能力値が同じ人がいた場合、毎回、前の人を取るようになっています。そこで、能力値が同じときはランダムに必要人数分取るようにしたいのですがお願いできますでしょうか。現状の方法は解決方法のところにコードを貼りました
Lhankor_Mhy

2020/01/17 09:04

Python のソートは安定ソートなので、ソート前の順序を保存します。 一方で、Key引数によって、比較関数を指定することができます。 https://docs.python.org/ja/3/howto/sorting.html#key-functions なので、ソートする前にシャッフルし、リストの1番目の要素だけをKeyにしてソートすれば、アルゴリズムを変えずにランダムに取れるのではないかと思います。 https://docs.python.org/ja/3/library/random.html#random.shuffle
yoshipiman

2020/01/20 06:30

返信が遅くなり申し訳ありません。 貼っていただいたURLを見て調べたのですがあまり分からなかったです。 最新の解決方法のコードが能力値順にソートして必要人数分取るコードです。 そこにコードを追加していただけないでしょうか。何度もすみません。これが最後の悩んでいることなのでよろしくお願いします。
yoshipiman

2020/01/21 07:58

いろいろと教えていただき本当にありがとうございました。 助かりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問