Continuity is The Father of Success

Androidアプリとかゲームとか。毎日続けてるものについて。

2つのシートを並べ替えて結合する処理

※昔書いた記事を某所から移行。


先日マクロで2つのファイルを結合して並べ替える処理を作ったので備忘録的に。 マクロって難しいですね。

Public Const MITSUMORI As String = "見積もり"
Public Const SHIRE As String = "仕入れ先"
Public Const KATABAN As String = "型番"
Public Const KINGAKU As String = "金額"

Sub Main()
    ' シートの用意
    Call ClearWorkSheets
    Call CreateWorkSheets
    Call CopyToWorkbook(SHIRE)
    Call CopyToWorkbook(MITSUMORI)
    
    ' ソート
    Call KatabanSort(SHIRE)
    Call KatabanSort(MITSUMORI)
    
    ' マージ処理
    Call KingakuTeknki
    
    MsgBox "完了!"
End Sub


' 前回読み込んだシートがあった場合に削除
Private Sub ClearWorkSheets()
    Application.DisplayAlerts = False
    With ThisWorkbook
        If SheetDetect(MITSUMORI) Then
            .Worksheets(MITSUMORI).Delete
        End If
        If SheetDetect(SHIRE) Then
            .Worksheets(SHIRE).Delete
        End If
    End With
    Application.DisplayAlerts = True
End Sub

' 作業用のシートを作成
Private Sub CreateWorkSheets()
    ' アクティブなシートを記憶
    Dim OldSheet As Worksheet
    Set OldSheet = ActiveSheet
    
    ' 見積もり用のシートを作成
    Dim NewMitsumoriSheet As Worksheet
    Set NewMitsumoriSheet = Worksheets.Add(After:=Worksheets(Worksheets.count))
    NewMitsumoriSheet.Name = MITSUMORI
    
    ' 仕入れ先用のシートを作成
    Dim NewShireSheet As Worksheet
    Set NewShireSheet = Worksheets.Add(After:=Worksheets(Worksheets.count))
    NewShireSheet.Name = SHIRE
    
    OldSheet.Activate
End Sub

' ファイルを開いてシートをコピー
Private Sub CopyToWorkbook(Target As String)
    Dim OldWorksheet As Workbook
    Dim TargetSheet As Worksheet
    Dim OpenFileName As String
    
    ' コピー先のワークシートを保持
    Set OldWorksheet = ThisWorkbook
    
    ' ファイルを開く
    MsgBox (Target & "用のファイルを選択してください")
    OpenFileName = Application.GetOpenFilename("Microsoft Excelブック,*.xlsx?")
    Workbooks.Open OpenFileName, ReadOnly:=True
    
    ' シートにコピー
    Set TargetSheet = ActiveWorkbook.Worksheets(1)
    TargetSheet.Cells.Copy OldWorksheet.Worksheets(Target).Range("A1")
    
    ActiveWorkbook.Close
End Sub


' シートを型番でソート
Private Sub KatabanSort(SheetName As String)
    Dim ActivateSheet As Worksheet
    Dim MaxRow As Long
    Dim MaxCol As Long
    Dim KatabanCol As Long
    
    ' 対象のシートの縦横サイズを獲得
    MaxRow = RowEnd(SheetName)
    MaxCol = RowEnd(SheetName)
    ' 型番の行を取得
    KatabanCol = getKataban(SheetName)
    
    If SheetName = SHIRE Then
        Dim KingakuCol As Long
        KingakuCol = getKingaku(SheetName)
        Call DeleteDuplicate(KatabanCol, KingakuCol, MaxRow)
    End If
    
    Set ActivateSheet = ActiveWorkbook.Worksheets(SheetName)
    ActivateSheet.Activate
    'ソートの実行
    Range("A1", Cells(MaxRow, MaxCol)).Sort (Cells(1, KatabanCol)), Header:=xlYes
End Sub

' 型番を比較して金額を転記
Private Sub KingakuTeknki()
    ' 型番の行を取得
    KatabanCol = getKataban(MITSUMORI)
    
    ' 転記先(見積もりシート)をアクティブにする
    Dim ActivateSheet As Worksheet
    Set ActivateSheet = ActiveWorkbook.Worksheets(MITSUMORI)
    ActivateSheet.Activate

    ' 型番の右隣の列に金額欄を追加
    Columns(KatabanCol + 1).Insert
    Cells(1, (KatabanCol + 1)) = KINGAKU
    
    Dim i As Long
    Dim j As Long
    Dim MitsumoriCount As Long
    Dim ShireCount As Long
    
    MitsumoriCount = RowEnd(MITSUMORI)
    ShireCount = RowEnd(SHIRE)
    
    Dim MitsumoriKataban As Long
    Dim ShireKataban As Long
    Dim MitsumoriKingaku As Long
    Dim ShireKingaku As Long
    
    MistumoriKataban = getKataban(MITSUMORI)
    ShireKataban = getKataban(SHIRE)
    MitsumoriKingaku = getKingaku(MITSUMORI)
    ShireKingaku = getKingaku(SHIRE)
    
    ' 見積もりシートと仕入れシートを比較し、一致するモノがあれば転記
    ' 高速化のためにソート済みであることを利用する
    For i = 2 To MitsumoriCount
        For j = 2 To ShireCount
            If Worksheets(MITSUMORI).Cells(i, MistumoriKataban) = _
                Worksheets(SHIRE).Cells(j, ShireKataban) Then
                ' 転記
                Worksheets(MITSUMORI).Cells(i, MitsumoriKingaku) = _
                    Worksheets(SHIRE).Cells(j, ShireKingaku)
                Exit For
            ElseIf Worksheets(MITSUMORI).Cells(i, MistumoriKataban) < _
                    Worksheets(SHIRE).Cells(j, ShireKataban) Then
                ' 次の行の確認へ
                j = j - 1
                Exit For
            End If
        Next j
    Next i
End Sub


' シートがあるかどうかを確認
Public Function SheetDetect(SName As String) As Boolean
    Dim sheet As Worksheet
    For Each sheet In ThisWorkbook.Worksheets
        If sheet.Name = SName Then
            SheetDetect = True
            Exit Function
        End If
    Next
End Function

' 1つの型番に複数の金額があったときに、高い方を残す
Public Sub DeleteDuplicate(KatabanCol As Long, KingakuCol As Long, CountEnd As Long)
    Dim i As Long
    Dim j As Long
    Dim count As Long
    
    With ActiveWorkbook.Worksheets(SHIRE)
        count = CountEnd
        
        For i = 2 To count
            For j = i + 1 To count
                If .Cells(i, KatabanCol) = .Cells(j, KatabanCol) Then
                    If .Cells(i, KingakuCol) > .Cells(j, KingakuCol) Then
                        .Rows(j).Delete
                    Else
                        .Rows(i).Delete
                    End If
                    j = j - 1
                    count = count - 1
                End If
            Next j
        Next i
    End With
    
End Sub

' シートの最終行を取得
Public Function RowEnd(SheetName As String) As Long
    RowEnd = ActiveWorkbook.Worksheets(SheetName).Range("A1").SpecialCells(xlLastCell).Row
End Function

' シートの最終列を取得
Public Function ColEnd(SheetName As String) As Long
    ColEnd = ActiveWorkbook.Worksheets(SheetName).Range("A1").SpecialCells(xlLastCell).Column
End Function

Public Function getKataban(SheetName) As Long
    getKataban = ActiveWorkbook.Worksheets(SheetName).Cells.Find(KATABAN).Column
End Function

Public Function getKingaku(SheetName) As Long
    getKingaku = ActiveWorkbook.Worksheets(SheetName).Cells.Find(KINGAKU).Column
End Function

Androidアプリ開発を始める 2020年春版

2019年のはこちら。 丸一年経ったので今年の知識の棚卸しも兼ねて。

blog.dr1009.com

はじめに

昨年版と同様に、本項の目的は下記2つです。

  • サーバーサイド開発等の経験があるエンジニアが、Android開発を始める際に参考となる資料をまとめる
  • 2020年で当たり前とされる技術を整理する

Androidアプリの開発環境を整える

AndroidStudioの導入

developer.android.com

必ず公式ドキュメントを参考にしてインストールしましょう。 最近では公式ドキュメントの大半を日本語で読むことができるようになっています。

開発を始めてみようと思ったら、ドキュメント通りに手を動かしてみることを強くお勧めします。

Flutter

2019年からの大きな違いの一つに、Flutterの存在感が増したことがあります。

flutter.dev

雑に書いてしまえば、Webアプリをベースとしたサービスのアプリであれば、FlutterによりAndroidアプリを開発してしまった方が早いかもしれません。 このため、開発を行う対象によってはKotlinによるAndroidアプリ開発を経ず、FlutterによるAndroidアプリ開発を始めてしまってよいと思われます。

flutter.dev

公式ドキュメントは英語になりますが、非常に懇切丁寧な説明がされています。 Flutterで開発されたアプリの一覧などもあるので、自分の作ってみたいアプリが明確な場合には、見比べて検討してみるとよいと思われます。

flutter.dev

開発する環境

Figmaの登場により、以前よりMacを選ぶ必要性が減ったように感じます。 ChromeBookでAndroidStudioを動かすことができるようになったこともあり、より自分な好きな環境で開発が行えるようになってきたと感じます。

developer.android.com

Androidの基礎知識

developer.android.com

このうち、一番最初に書いてある「Androidアプリのセキュリティの話」と「アプリのコンポーネント」は目を通しておくことをお勧めします。 アプリのセキュリティについて知ることで、「アプリのデータをどのように保存するべきか」を考えることができるようになります。アプリでデータを保持する際に、ベースとなる知見です。 また「アプリのコンポーネント」の中では、「アクティビティ」を特に読み込んでください。そのほかはすぐさま使うことは少ないかもしれませんが、機能開発の中で詰まった時に「あの話に関係があるのかな?」と気づくきっかけにすることができるため、目を通しておくことをお勧めします。

アクティビティのライフサイクル

Understand the Activity Lifecycle  |  Android Developers

AndroidアプリをKotlinで作る場合でも、Flutterで作る場合でも「アクティビティのライフサイクルのコンセプト」まで熟読することをお勧めします。 アプリの起動状態が異なるケースで発生するバグのトラッキング、ユーザーが別のアプリを立ち上げる時に気をつけることなどはアクティビティのライフサイクルをベースに理解することができます。

昨年同様、アプリケーションのライフサイクルやフラグメントのライフサイクルは開発が進んできたら理解していけばよいと思います。 もしもそれらを理解したいなと思ったら、Android Architecture Componentsの導入とGoogleがお勧めするアーキテクチャの導入を検討してみてください。

developer.android.com

Android Developerの抑えどころ

極めて個人的な意見となりますが、下記のページは適宜読み込むとよいと思います。 Flutterでアプリを開発する場合でも、1〜3は参考になるのではないでしょうか?

  1. Understand Tasks and Back Stack  |  Android Developers
  2. Intents and Intent Filters  |  Android Developers
  3. Input events overview  |  Android Developers
  4. Layouts  |  Android Developers

Material Design

Material ThemeのバージョンアップがGoogle I/O 2019で発表され、Dark Themeなどが正式に導入されました。

material.io

個人的に2019年に比べてAndroidアプリ開発者が覚えるべきことが大幅に増えたなと感じているのですが、その際たるものがMaterial Designに関してです。

material.io

Androidアプリ開発の中で、これまではAndroidアプリの実現したい機能に対応するUIパーツを探して当てはめるようなことがよく行われていました。 しかしAndroid向けのMaterial Designライブラリが十分な完成度となった現在、エンジニアにはMaterial Designの「理由」を理解しながらパーツを選定する技能が求められつつあります。

1例としてアプリのナビゲーションの選択を挙げてみます。 パッとアプリのナビゲーションを行うUIパーツの名前は思い浮かぶでしょうか? どのUIパーツを選択しますか? なぜそのパーツを選択するのでしょうか?

material.io

Material Designを確認すると、上記のように「UIパーツ」と「利用シーン」が明確に定義されています。

このためMaterial Designをデザイナーや企画者との共通言語として利用できるよう、理解を深める必要性が高まっています。 かつ、選択したGUIアーキテクチャがUIパーツの状態を適切にハンドリングできるよう、各UIパーツのAPIにも知見を深める必要があると言えます。

JavaとKotlin

Kotlinを利用しましょう。 デメリットとしてはJavaのみでアプリを作るより1~1.5MBほどアプリサイズが大きくなることがあげられますが、それを補って余りあるほどの開発のしやすさがあります。

Kotlin and Android  |  Android Developers

少し横道に話はそれますが、Androidの開発技術の認定なども始まっています。 (たしか)英語でのコースとなるのですが、興味と時間があればコースの受講と認定証の取得を目指してみてもよいのではないでしょうか。

Google Developers Certification

サンプルリポジトリ

Androidアプリの設計などの学習をしたいケースもあると思います。 その際には、下記のリポジトリを確認することをオススメします。

DroidKaigi 2020については、DroidKaigi App Fireside Chatがあるので試聴してみるのもよいと思います。


DroidKaigi App Fireside Chat

個人的にはAndroid Architecture ComponentsのMVVMが好きなので、2020年の構成は理解しやすかったです。

開発端末

AndroidStudioのエミュレーターが高速なため、メモリとCPUに余裕のあるマシンであれば実機がなくてもよいのではないかなと思っています。 エミュレーターの起動速度やアプリの動作速度、位置情報の変更など開発で必要な機能は十分です。

ただカメラを使ったアプリを作る場合には、実機を用意することを考えてみてください。 逆に言えば、それ以外の機能を主とするアプリであればエミュレーターによる開発で大半を賄うことができます。

なお、個人的に開発端末としてお勧めなのは Pixel 3a です。 今年の6月ごろにPixel 4aが出るんじゃないかなと思っているので、出たらPixel 4aにするのがよいのではないかと思っています。

国内版SIMフリー Google Pixel 3a 64GB Just Black

国内版SIMフリー Google Pixel 3a 64GB Just Black

  • メディア: エレクトロニクス

国内版SIMフリー Google Pixel 3a 64GB Clearly White

国内版SIMフリー Google Pixel 3a 64GB Clearly White

  • メディア: エレクトロニクス

終わりに

去年よりシンプルに書こうかと思っていたのですが、なんだかんだ同じぐらいになっちゃいました。 ライブラリ編はまた別にまとめようと思います。

ライブラリ編

blog.dr1009.com

結論を出す「こと」

たとえば10人のチームに属しているとする。 この時、何かを決めようとするとどうなるだろう。

  • case-1
    • あなたの隣のだれかと1時間会議室に籠もって議論をし、そこで結論を出し、全体に対して「結論を出しました」と宣言する。その結論は受け入れられるだろうか?
  • case-2
    • あなたの隣のだれかと1時間会議室に籠もって議論をし、そこで結論を出し、全体に対して「提案書を作成しました」と宣言する。その結論は受け入れられるだろうか?

実際にはどちらも受け入れられることはあるし、受け入れられないこともある。 このとき、受け入れられない場合の「理由」が全く違うのではないか、という話を書く。

case-1をイメージしてみる。

受け入れられないと言うより、反発が発生する。もしくは、なぜその結論になるのか納得がされない。 つまり「2名の意見を全体の意見と見なす合意が取れていない」状況で、『これが結論である』と表明されることに対する不快感によって拒絶される。 もしくは、2名の結論を出した過程に対して疑問が挟まれて、拒絶される。

このため、"あなたと隣のだれか"が検討委員のような、検討を行う役割であれば話が全く変わってくる。 それは当然の活動であって、特段意識されるようなものでもない。 10人のチームの中で決められた役割を果たしているものだ。

case-2をイメージしてみる。

受け入れられないというより、手直しが発生する。もしくは、提案を出す権限がないということになる。 というより、この例はずるくて「提案書」がどういったものか明示していないのに自明のものとして扱っている。 「提案書」と言って一発で通じるのならば、それはそのチームで「提案書」がどういったものか明示的に/暗黙的に同意されているはずだ。

明示的に/暗黙的に定められたステップに従っているのでも、case-1と異なるのは、明らかに「このチームの合意にしたい」ことを伝えている点だろう。 case-1とcase-2で提出されている「案」の品質に違いはない。単に「案」の品質でもって全知全能の人が判断するのであれば、それは手順が違っても同じ結論になるはずだ。 けれどそうはならないことは、容易に想像できる。

チームがどう結論を出すかは、そのチームが明示的に/暗黙的に持っている「どういう手順をもって結論を作るか」という認識に引きづられる。 もしかすると、それは『年長者が判断する』かもしれないし『リーダーがコストとベネフィットから判断する』かもしれない。 『年長者が判断する』であればその年長者の過去の決断にそう話とするだろうし、『リーダーがコストとベネフィットから判断する』であればコストとベネフィットの試算を添付するだろう。

つまり、何らかの結論を出そうと考えるときには、その結論を結論とするための方法を考える必要がある。 逆に言えば、結論とするための方法を考えていない「案」は、単なる「案」であって合意のための検討がされることはない。

2重に物事を考えることが必要だなと、痛感しているこの頃。