Kuzunoha-NEのブログ

プログラミングなどの勉強をしてます

【Python】イテレータってのをやってみた

こんばんは、葛の葉です。

今回はPythonイテレータをやってみました。

イテレータは要素を一つずつ出力するオブジェクトを生成することのようです。

ちょっと前につくったPythonで特定文字以降の文字を削除する(正規表現を使わない)イテレータで実装します。

kuzunoha-ne.hateblo.jp

実行環境

Python3.6.5

コードはこんな感じ

class Splitter(object):
    def __init__(self, array, waste_word):
        self.array = array
        self.waste_word = waste_word

    def __iter__(self):
        for i in self.array:
            if self.waste_word in i:
                yield i.split(self.waste_word)[0]
            else:
                yield i

dinners = ['チキングリル', 'シェフの気まぐれサラダ(工場生産)', 'ドラゴンのしっぽビール(発泡酒)', 'スコーン']

spliter = Splitter(
    array=dinners,
    waste_word="("
    )

new_array = []

for i in spliter:
    new_array.append(i)

# リスト内包表記なら 
# [new_array.append(i) for i in spliter]

print(new_array)

↓出力結果↓

['チキングリル', 'シェフの気まぐれサラダ', 'ドラゴンのしっぽビール', 'スコーン']

出来ました!!

イテレータは要素の出力が一回一回になるので、メモリを圧迫しにくいそうです。

何がどう良いのかはこれから調べてみますけどね(´;ω;`)

【Ruby => Python】たい焼きクラスを作ってみる

こんばんは、葛の葉です。こんな動画があったんです。

www.youtube.com

前に紹介した本の著者だった!びっくり!

kuzunoha-ne.hateblo.jp

qiita.com

ちょっとそれらの動画やページをみつつ、RubyからPythonに移植できるか、やってみました。

[Step 1. 「あんこ」の種類を保持できるようにする]

'''
Python
https://www.youtube.com/watch?v=HsivL1JBRaw
RubyのこれをPythonに移植してみよう!
'''
import unittest


class Taiyaki:
    def __init__(self, anko):
        self.anko = anko


class TaiyakiTest(unittest.TestCase):

    def test_taiyaki(self):
        taiyaki_1 = Taiyaki('あんこ')
        self.assertEqual('あんこ', taiyaki_1.anko)
        taiyaki_2 = Taiyaki('白あん')
        self.assertEqual('白あん', taiyaki_2.anko)


if __name__ == '__main__':
    unittest.main(exit=False)

Step 2. 「大きさ」を保持できるようにする

'''
Python
https://www.youtube.com/watch?v=HsivL1JBRaw
RubyのこれをPythonに移植してみよう!
'''
import unittest


class Taiyaki:
    def __init__(self, anko, size):
        self.anko = anko
        self.size = size


class TaiyakiTest(unittest.TestCase):

    def test_taiyaki(self):
        taiyaki_1 = Taiyaki('あんこ', 'ふつう')
        self.assertEqual('あんこ', taiyaki_1.anko)
        self.assertEqual('ふつう', taiyaki_1.size)

        taiyaki_2 = Taiyaki('白あん', '大きい')
        self.assertEqual('白あん', taiyaki_2.anko)
        self.assertEqual('大きい', taiyaki_2.size)


if __name__ == '__main__':
    unittest.main(exit=False)

Step 3. [自分の状態を文字列として返せるようにする]

'''
Python
https://www.youtube.com/watch?v=HsivL1JBRaw
RubyのこれをPythonに移植してみよう!
'''
import unittest


class Taiyaki:
    def __init__(self, anko, size):
        self.anko = anko
        self.size = size

    def to_s(self):
        return 'あんこ: {anko}, 大きさ: {size}'.format(anko=self.anko, size=self.size)


class TaiyakiTest(unittest.TestCase):

    def test_taiyaki(self):
        taiyaki_1 = Taiyaki('あんこ', 'ふつう')
        self.assertEqual('あんこ', taiyaki_1.anko)
        self.assertEqual('ふつう', taiyaki_1.size)
        self.assertEqual('あんこ: あんこ, 大きさ: ふつう', taiyaki_1.to_s())

        taiyaki_2 = Taiyaki('白あん', '大きい')
        self.assertEqual('白あん', taiyaki_2.anko)
        self.assertEqual('大きい', taiyaki_2.size)
        self.assertEqual('あんこ: 白あん, 大きさ: 大きい', taiyaki_2.to_s())

if __name__ == '__main__':
    unittest.main(exit=False)

残りは…

残りは君自身の目で確かめてみてくれ!

単体テストしながらコード書いたのは楽しかった。

インスタンスメソッドを追加することで機能を追加していくところが楽しかった。

Rubyの勉強もPythonの勉強も出来たから、もしかして移植ってなかなか勉強になるんじゃないのかな?って思いました。

G Suite People Analytics セミナーに参加して思ったこと

こんばんは、葛の葉です。

11/13に、実はこういうイベントに参加していました。

www.dsk-cloud.com

ここではGoogleさんのAI活用事例、とりわけ、社員の行動をデータ化し、それを機械学習させることで、業務円滑化を図っている…というお話も面白かったのですが…

これからの仕事、働き方についてお話をしていただいた、プロノイア・グループ株式会社のピョートル・グジバチさんのお話が面白かったです。

プロノイア・グループさんのHPはこちら

www.pronoiagroup.com

ものづくりの時代が終わり、仕組みづくりの時代になった。

GoogleFacebookの二社は、テレビ局やラジオといった巨大であるメディアの企業に勝ったのはどうしてか?二社ともそのメディアという業界においては全くの未経験であったのに。という問いかけをしてから、「業界未経験者が業界を壊していくものなのだ」という風のおっしゃっていました。

二社において、共通した項目というものは「マネタイズをしていない」ということでした。そのことからイノベーションを起こす組織というものは「強欲な組織」より「利他的な組織」であるということでした。また、これから求められる組織もそういうものであると、そのように仰っていました。

それから「クローズされた組織」より「オープンな組織」が生き残っているともおっしゃっていました。Googleに、しばしば女子高校生が出入りしているようで、これは世界的に「女性エンジニア」が少ない現状に対して、女性にITエンジニアリングに興味をもってもらいたい、ということで、Googleが取り組んでいる「Mind the Gap」という活動のようです。このように、組織と個人が身近になれるような、そういった取り組みがオープンな組織となる、と、そのようにおっしゃっていたと思います。

またピョートルさんは続けて「トップダウン方式よりボトムアップ方式が良い」「社畜優遇のピラミッド構造が終わった」「鵜飼いのマネジメントより羊飼いのマネジメント*1」などなど、「かつて」と「これから」を対比させながら、組織のあり方について仰っていました。よくよくそのお話を聞いていると「会社の社員個人個人が幸せに仕事が出来ているとそれがイノベーションに繋がる」ということをお話されていたような気がします。

また、プロノイア・グループさんは組織づくりにおいて、以下の4つのことが大事とのことを仰っていました。

  1. [心理的安全性] 自分らしく出社することができるか

  2. [信頼性] 社員がお互いに信頼することが出来るか

  3. [構造、役割の透明化] 自分がどんな立ち位置かわかりやすいか

  4. [仕事の意味] 仕事が与える影響はどんなものであるか

またプロノイア・グループさんでは以下の3つ文化を大切にしているとのことでした。

Play work (遊ぶように働く)

Implement first (初めての前例になる)

Offer Unexpected (予期しない提供)

*1これはスライドがあり、鵜飼いは鵜に紐をつけて魚を取らせるような、社員を言い聞かせて動かすというものに対して、羊飼いは、自由にのんびり雑草を食べる羊とそれを見守る羊飼いというイラストで対比されていました。

ピョートルさんのお話を聞けて思ったこと

今回のピョートルさんのお話の間はとにかく「笑い」がありました。また、プロノイア・グループさんのPIO(先に記載した3つの文化の頭文字に関連している)というヒヨコのキャラクターの似顔絵もピョートルさんそっくりに描かれていて、楽しそうに仕事していることが伝わってきました。

「自分らしく仕事が出来る」って、これほど素晴らしいものがあるだろうか、と思いました。よく私も「変わってる」とか言われてきました。そのたびに「普通」になろうと思ってあれこれやってきましたが、ついぞそれは叶わず。最近になって諸々と拗らせて「自分らしさ」を見つけようとは思ってますが、まあ見つかりません。「右向け右」を「組織」でやると随分と「矯正」されると思います。まぁそれくらい「組織」とか「集団」ってのは強いと思うんですね。

だからこそ、「組織が多様性を認めている」って、大きなことなんだと思います。

ただまぁ、最近でこそ「多様性は善」ということが浸透しつつありますが、まだまだ「出る杭は打たれる」のが現状でもあるんだと思います。私、正直、イノベーションがどうって、よくわからないです。そりゃあ、「みんな同じ」「全員ゼネラリスト」じゃイノベーションなんて生まれないでしょう。そりゃあ、もう、みんな同じ発想になるように仕込まれるですから。

今すぐ、イノベーションが起きなくても、それでも、最初は多様性を認める組織が増えればいいんじゃないかなって思ってます。個人として、「多様性を認める組織」を認めていくと言いますか。

僕自身が今できることは、そういったことなのかな、と思いました。

MySQL 5.7.22 のORDER BYの順番について

MySQL 5.7.22 のORDER BYの順番について

こんばんは、葛の葉です。

SQLも出来ないの?そんなんじゃ甘いよ。って言われたのでSQLもやってます。ナキソーです。

そこで、Dockerを使ってMySQL 5.7.22のイメージを作って環境を作ってSQLの勉強をしているんです。また、参考書として、下記の物を使用しています。結構砕けた文章なので、読んでいて面白いですよ~ただ、2008年が最新なので古いところが難点かもしれません。 これも読み終わったらレビューをしてみましょうかね。

ORDER BYでのソート順について

上記の本のP.255には、数字とアルファベットと記号が入ったテーブルでORDER BYでソートして、その並び順を確認する、というものがあったと思うのですが、ひらがな、カタカナ、漢字、半角カナ、全角数字も入れた場合はどうなるか、という点は書かれていなかったと思います。ですので、ちょっとやってみました。

CREATE DATABASE sandbox;

USE sandbox;

CREATE TABLE test(
    test_char VARCHAR(30)
);

INSERT INTO test (test_char)
VALUE
('0'),('1'),('2'),('3'),
('A'),('B'),('C'),('D'),
('a'),('b'),('c'),('d'),
('!'),('@'),('#'),('$'),
('%'),('^'),('&'),('*'),
('('),(')'),('-'),('_'),
('+'),('='),('['),(']'),
('{'),('}'),(';'),(':'),
('\''),('\"'),('\\'),('|'),
('\`'),('~'),(','),('.'),
('<'),('>'),('/'),('?'),
('ア'),('イ'),('ウ'),('エ'),
('あ'),('い'),('う'),('え'),
('ア'),('イ'),('ウ'),('エ'),
('亜'),('居'),('兎'),('絵'),
('0'),('1'),('2'),('3'),
(NULL);

どうでもいいことなんですけどINSERT INTO table名 VALUE(値);でもいけますね。要するにカラム名を省略するタイプです。なんか、書くほうが私は好きかも。もう一つどうでもいい話ですが、INSERT INTO table名 (column名) VALUE (値1),(値2),(値3);で複数レコード作れます。スゴイネ。

そして、SELECT * FROM test ORDER BY test_char;を実行するとこんな感じ。

+-----------+
| test_char |
+-----------+
| NULL      |
| !         |
| "         |
| #         |
| $         |
| %         |
| &         |
| '         |
| (         |
| )         |
| *         |
| +         |
| ,         |
| -         |
| .         |
| /         |
| 0         |
| 1         |
| 2         |
| 3         |
| :         |
| ;         |
| <         |
| =         |
| >         |
| ?         |
| @         |
| A         |
| a         |
| b         |
| B         |
| c         |
| C         |
| d         |
| D         |
| [         |
| \         |
| ]         |
| ^         |
| _         |
| `         |
| {         |
| |         |
| }         |
| ~         |
| あ        |
| い        |
| う        |
| え        |
| ア        |
| イ        |
| ウ        |
| エ        |
| 亜        |
| 兎        |
| 居        |
| 絵        |
| 0        |
| 1        |
| 2        |
| 3        |
| ア         |
| イ         |
| ウ         |
| エ         |
+-----------+
65 rows in set (0.00 sec)

さもありなんというか、まぁやっぱり日本語は後ろに来るのね、という印象です。全体をみると、記号、数字、記号、英字、記号となっていておもしろいですね。なんでこうなってるんだろう?まぁアルファベット順になる、数字順になるってのがわかればそれでいいかなぁって思います。記号をソートしたいって思うことないと思うし~

ところで…これであってるんかな(^ω^;)

| @         |
| A         |
| a         |
| b         |
| B         |
| c         |
| C         |

大文字が最初にくるはずなんだけど…AabBcCになってるね…ウーン…Dockerの問題?どういうことだろう…

Rubyのキーワード引数というヤツ

Rubyのキーワード引数というヤツ

こんばんは、葛の葉です。

お勉強したまへ、というお達しがありました。あっふーん…(達し)

というわけで最近はこの書籍を使って勉強しております。

キーワード引数というヤツ

なんか知らんけど関数を作る時に引数名を作ることが出来るようです。へぇ。Pythonにもあったねたしか。

// Pythonだと…

def animal(momonga, dog='ももちゃん', cat='めけめけ王子三世'):
    return cat


print(animal('neko'))

>>>めけめけ王子三世

cat = 'めけめけ王子三世'なのわかりやすい。

// Rubyだと…

def animal(momonga, dog: 'ももちゃん', cat: 'めけめけ王子三世' )
    cat
end

p(animal('neko'))

>>"めけめけ王子三世"

返り値は:catじゃなくてcatにしないと駄目?:catじゃないの?

def animal(momonga, dog: 'ももちゃん', cat: 'めけめけ王子三世' )は省略形で、正しく書くならdef animal(momonga, {:dog => 'ももちゃん', :cat => 'めけめけ王子三世'}こうなんじゃないか?やってみよう。

def animal(momonga, {:dog => 'ももちゃん', :cat => 'めけめけ王子三世'}
    cat
end
p(animal('neko'))

sand.rb:9: syntax error, unexpected {
def animal(momonga, {:dog => 'ももちゃん', :c...
                    ^
sand.rb:11: syntax error, unexpected keyword_end, expecting end-of-input
(Google翻訳[2018/11/2])sand.rb:11:構文エラー、予期しないkeyword_end、入力の終了を予期する

わがんね😭

所謂シンボルではなくて、ブロックとしてみなされているのかな?

この本については後ほどレビューしてみます

先程記載した本派中々面白いです。5章まで読みましたが、テスト駆動開発で行っていますので、前回、PythonでUnittestについて書いたのですが、より理解が深まったと思いました。この本のテストはRubyで書かれているので、Pythonで書き直してみるのも楽しいかも知れませんね。それと、Rubyはあまりやったことなかったので、知らないところはやはり出てきました。が、親切に書いてくれているので、Rubyちょっとしか触ったこと無いって人にも向いていると思います。

kuzunoha-ne.hateblo.jp

Google Apps Scriptで出退勤の発報botを作った

Google Apps Scriptで出退勤の発報botを作った

こんばんは、葛の葉です。

ちょっと前に、GoogleAppsScriptでdiscordのbotを作ったのですが、なんか社長が偉く気に入ったらしくブログの記事に書いてちょんまげって言われて、まぁ、書くことにしました。

どういうbotを作ったのか

私の会社では下図のようにGoogleSpreadSheetsを使った出退勤の表がありまして…

www.google.com

f:id:Kuzunoha-NE:20181023111025j:plain

私、葛の葉は置いといて、他の人たちがまぁインターン生さんです。桃太郎さんとかキャプテン鬼ヶ島さんがそうですね。インターン生さんたちに、この表に時刻を書き込ませて、シフトの決定をしてもらっています。また、シフトを組むのもインターン生さんが決めることになっています。そのため、インターン生さんが好きな時に好きに出勤日と日時を決められるということができます。

また、お仕事の連絡にチャットツールを用いておりまして、それがDiscordなんですね。

discordapp.com

今回作ったbotは、インターン生さんがその出退勤表に一週間以内に出勤の予定を書き込んだ時に、DiscordBotが私宛に発報するというものになります。


10/22現在で、桃太郎さんが10/23 10:00-16:00として出社予定日時を記載した場合

「発報しているシーン」

f:id:Kuzunoha-NE:20181023115107j:plain

「チャットツールDiscordに新着メッセージが来ているシーン」

f:id:Kuzunoha-NE:20181023115557j:plain

ちなみに、セルをコピー&ペーストで張り付けた場合は内容: [予定なし] → [予定なし]と表示されちゃいます。これはちょっと直し方わからんです。ざんねん。

botの作り方

GoogleSpreadsSheetsのGoogleAppsScriptとDiscordのWebhookの連携。

これは過去記事に書いているので、そちらを参照してほしいです。

そちらのコードのうち、function discord(message)の関数を使います。他三つの関数は使いません。(似たようなのはつくるんですけどね)

kuzunoha-ne.hateblo.jp

// Discordに送信する関数
function discord(message) {
    const url        = 'さっきコピーしたwebhooksのURL';
    const token      = 'さっきのURLの中のtokenの文字列';
    const channel    = '#general';
    const text       = message;
    const username   = 'bot';
    const parse      = 'full';
    const method     = 'post';

    const payload = {
        'token'      : token,
        'channel'    : channel,
        "content"    : text,
        'username'   : username,
        'parse'      : parse,
    };

    const params = {
        'method' : method,
        'payload' : payload,
        'muteHttpExceptions': true

    };

   response = UrlFetchApp.fetch(url, params);
}

編集されたセルの行と列の番号を取得する。

GoogleSpreadSheetsにはfunction onEdit(e){}というものがあります。詳しくは以下のリンクを参照してください。この関数はそのスプレッドシート内(ExcelでいうBook内)で編集された様々な情報を取得できる関数です。

Event Objects  |  Apps Script  |  Google Developers

function onEdit(e){}の関数内でe.range.getRow();関数を使用すると行番号、e.range.getColumnIndex()関数を使用すると列番号を取得できます。

onEdit(e)関数はそのスプレッドシートのすべてのシートが対象になります。つまり、新しい月のシートを作成してもこのプログラムは動作します。ヤッタゼ。

function onEdit(e){
  //e.****は更新のシートやセルの情報
  var change_row_num = e.range.getRow();
  var change_colum_num = e.range.getColumnIndex();
}

編集された氏名と日付を取得する。

編集された行と列が取得できたので、それを元に編集された個所の日付と氏名を取得しましょう。まずは氏名から。

   var change_name = SpreadsheetApp.getActiveSheet().getRange(2, change_colum_num).getValue();

SpreadsheetApp.getActiveSheet().getRange(行, 列).getValue()という関数を使用して、編集されたシートから氏名を取得します。.getRange(行, 列)は行数を、は列番号を指定します。今回、2としているのは、該当のシートの二行目が名前欄となっているからです。今回のコードをそのまま使うなら、この辺りを変更しないとダメかも?

次に日付になります。

    var unformat_change_date = SpreadsheetApp.getActiveSheet().getRange(change_row_num, 2).getValue();
    var change_date = Utilities.formatDate(unformat_change_date, "Asia/Tokyo", "yyyy/MM/dd");

また、編集されたシートから日付を取得します。2としているのは、該当のシートの二列目が日付欄となっているからです。ただ、このまま値を取得しても、それをdate型として扱うことができません。編集された日付一週間以内を区別するためにdate型にしてあげる必要があります。そのため、Utilities.formatDate(unformat_change_date, "Asia/Tokyo", "yyyy/MM/dd")という関数を使用します。以下も参照してみて下さい。

日時の設定  |  AdWords scripts  |  Google Developers

f:id:Kuzunoha-NE:20181023151950j:plain

当日を含めた一週間の日付データを取得しリストに格納する。

新しい関数を作ります。関数にしなくてもよいですが、とりあえず機能としては分けたかったので別関数にしました。

書き込み時点でのnew Date()を取得します。それにより、書き込み時点での当日を取得しています。それをloop文回し、当日を含めた8日分取得します。ちなみにloop文でvar i = 0にしようとしたらエラー吐きました。なんでだろう?

function this_week_days_list() {
  var today = new Date();
  var this_week = new Array();
  for(var i = 1;  i < 9;  i++){ /* var i = 0 ではだめらしい */
    var one_day = new Date(today.getYear(), today.getMonth(), today.getDate() + i - 1); 
    var format_today = Utilities.formatDate( one_day, "Asia/Tokyo", "yyyy/MM/dd");
    this_week.push(format_today);
  };
  return this_week
};

この関数をfunction onEdit(e){}内で呼び出してあげてます。

var this_week = this_week_days_list();

日付が当日を含めた一週間(8日間)の中に存在しているかを確認する。

this_week(list)に当日を含めた一週間(8日間)が格納されています。この中にchange_date(日付)が入っているかを確認します。リスト.indexOf(date型)とすると、引数の値がリスト内にあるかどうかを判定し、あれば0,なければ-1を返します。詳しくは以下のリンクを参照してください。

indexOf メソッド (Array) (JavaScript)

リスト内にその日付がないなら-1が返されます。ですので、条件分岐として-1の時は何もしない、という命令をします。何もしない命令文は;らしいです。

developer.mozilla.org

  if(this_week.indexOf(change_date) == -1){
    ; // 何もしない
  }else{
    .............-1じゃなかった時の実行文...............
  }

セルの編集前の値と編集後の値を取得する。

前述のif文のelse以降は、編集された日付が一週間以内のものであるということになり、本格的な動作はここからになります。

e.oldValuee.valueを使うことで、セルの編集前の値と編集後の値を取得することができます。詳しくは以下のリンクを参照してください。セルの中身が空の場合はundefinedになりますので、その場合は[予定なし]という値で変数を書き換えます。

Event Objects  |  Apps Script  |  Google Developers

    //編集前の値を取得
    var old_value = e.oldValue;
    if (old_value != undefined){;}else{
      old_value = "[予定なし]"
    };

    //編集後の値を取得
    var change_value = e.value;
    if (change_value != undefined){;}else{
      change_value = "[予定なし]"
    };

Discordのwebhookを使って送信する。

必要な条件や情報は揃ったのであとはstr型としてメッセージを作ります。

    var message = "";
    message += "名前:  " + change_name + "  ";
    message += "日付:  " + change_date + "  ";
    message += "内容:  " + old_value + "  →  " + change_value;
    discord_bot(message);

GASを通して特定のユーザーにメンションを送りたい場合。

APIを通してdiscordで送信するとき、特定の人にメンションとして送りたい場合は開発者モード(デベロッパモード)になる必要があります。やり方は以下のリンクの通りです。開発者モードにて、メンションを送りたい相手のユーザーIDを取得します。数字で18桁のようです。

support.discordapp.com

messageにこのような形で入れてあげてください。<@xxxxxxxxxxxxxxxxxx>(xxxxxxxxxxxxxxxxxxは18桁のユーザーID)

    var message = "";
    message += "<@xxxxxxxxxxxxxxxxxx> ";
    message += "名前:  " + change_name + "  ";
    message += "日付:  " + change_date + "  ";
    message += "内容:  " + old_value + "  →  " + change_value;
    discord_bot(message);

ソースコードはこんな感じです。

function onEdit(e) {
  //e.****は更新時のシートやセルの情報
  var change_row_num = e.range.getRow();
  var change_colum_num = e.range.getColumnIndex();
  
  try{
    var change_name = SpreadsheetApp.getActiveSheet().getRange(2, change_colum_num).getValue();
  }catch(e){
    //log用日付の取得
    var today = Utilities.formatDate( new Date(), "Asia/Tokyo", "yyyy/MM/dd HH:mm:ss");
    Logger.log("名前の参照できない箇所での操作を検知" + today + "\n");
    return
  }
  //GoogleSpreadSheetの日付が特殊な記載方法ため、フォーマット例(Tue Jul 17 00:00:00 GMT+09:00 2018)
  try{
    var unformat_change_date = SpreadsheetApp.getActiveSheet().getRange(change_row_num, 2).getValue();
    var change_date = Utilities.formatDate(unformat_change_date, "Asia/Tokyo", "yyyy/MM/dd");
  }catch(e){
    var today = Utilities.formatDate( new Date(), "Asia/Tokyo", "yyyy/MM/dd HH:mm:ss");
    Logger.log("日付の参照できない箇所での操作を検知" + today + "\n");
    return
  };
  
  //今週の日付8つ分の日付(当日を含むため8日)が入ったリストを取得する。
  var this_week = this_week_days_dict();
  //もし日付内に存在しなければ何もしない。
  if(this_week.indexOf(change_date) == -1){
    ;
  }else{
    //編集前と編集後のセルの値を取得
    var old_value = e.oldValue;
    if (old_value != undefined){;}else{
      old_value = "[予定なし]"
    };
    var change_value = e.value;
    if (change_value != undefined){;}else{
      change_value = "[予定なし]"
    };    
    
    var message = ""
    message += "<@xxxxxxxxxxxxxxxxxx> ";
    message += "名前:  " + change_name + "  ";
    message += "日付:  " + change_date + "  ";
    message += "内容:  " + old_value + "  →  " + change_value;
    discord_bot(message);
  };
};

function this_week_days_dict() {
  var today = new Date();
  var this_week = new Array();
  for(var i = 1;  i < 9;  i++){
    var one_day = new Date(today.getYear(), today.getMonth(), today.getDate() + i - 1);
    var format_today = Utilities.formatDate( one_day, "Asia/Tokyo", "yyyy/MM/dd");
    this_week.push(format_today);
  };
  return this_week
};

function discord_bot(message) {
   省略
}

なんかtrycatchが増えてますが、実際はそういう感じで使ってる感じです。Logger.logdiscord_botに変更してもらってもいいのかも知れないです。そうしたらDiscordにエラーのログが出力されます。

あとがき

botを作ったきっかけ

前述の通り、出勤の日付は好きな時にインターン生さんが自分で決めることが出来ます。そこで少し困ったのが当日のAM01:00やAM02:00に出勤の予定を記入するという人がいました。当日の朝に更新されても、こちらも準備とかがあるので急な決定は困ったところがありました。

また、会社の事務所がスペースが狭くインターン生さんは少人数しかいれられないのですが、前日までは人数的にスペースの問題はないと思っていたら、当日の朝確認をしてみたら予定が結構増えていてビックリすることがありました。

そのため、インターン生さんにチャットツールを使って「出勤予定日を早めに連絡してほしい」旨をお伝えしていたのですが、伝えた当日から連絡がないということがあり、ホトホト困りました。コミュニケーションがとても難しいということ実感した瞬間でもありました。

であるならば、botを使って、シートに更新があったタイミングでデータを取得して、発報してもらうような仕組みを考えました。これで少なくとも私の確認が漏れるということはなくなります。

また、Discordというチャットツールとして出力されるので、編集されたタイミングがわかりやすいです。最もGoogleSpreadSheetsは編集履歴が残っているのですが、編集があったタイミングで確認できるというのはちょっといいかもと思いました。

さいごに

本当に必要なのは人間と人間のやり取りであって、botはきっかけレベルでいいと思うんです。そもそも、私とインターン生さんとの間のコミュニケーションがうまく行ってないのが問題だから。とはいえ、最近は気を使ってくれてるのか、それとも願いが届いたのか、インターン生さんもちゃんと連絡してきてくださるようになって、このbotそのものもそこまで重要な存在にならなくなってるのかなぁとおもってたりします。

唐突にうちの会社のあっぴるが始まる

なんとうちの会社では社員さんを募集中です。募集の内容は以下の通り。

【Web/ゲーム開発エンジニア】スタートアップで自由に開発

【企画職・マネージャー候補】あなたの「良いね」を形にする

Pythonで選択ソートアルゴリズムを作ろうの巻

Pythonで選択ソートアルゴリズムを作ろうの巻

こんにちは、葛の葉です。 今回は選択ソートについて、書いていきます。

選択ソートアルゴリズム

選択ソートについては以下を参照

選択ソート - Wikipedia

作ったの

def selection_sort(arrs):
    for i in range(len(arrs)):  # (1)
        min_num = min(arrs[i::])   # (2)
        j = arrs.index(min_num)
        (arrs[i], arrs[j]) = (arrs[j], arrs[i])  # (3)
    return arrs


test = [1, 2, 5, 8, 6, 7, 3, 4, 9]

print(selection_sort(test))

(1) … i はindexになりますね。

(2) … min(arrs[i::])arrs[i::][i::]iのindexから最後の要素までという意味になります。i~最後の要素までで一番小さいもののindexを取得します。

(3) … (arrs[i], arrs[j]) = (arrs[j], arrs[i]) は変数の交換ですね。Pythonらしい書き方になります。

追伸

アルゴリズム…これってダメなんかな…