2022年3月26日土曜日

MaxBy & MinBy in .NET 6

どうも、もりもりです。

今回は.NET 6で追加されたLINQのMaxBy / MinByについてメモ。
.NET 6 より前ではどうしてた?代用できるメソッドはあるの?といったところもあります。

まずはMaxBy / MinBy (.NET 6)

こんなListがあったとして

new List<Person>()
{
    new Person(Name: "Ichiro", Age: 47),
    new Person("Jiro", 47),
    new Person("Saburo", 46),
    new Person("Siro", 41),
    new Person("Goro", 35),
    new Person("Rokuro", 35),
};

MaxBy、MinByを呼んでやると

var maxAgePerson = People.MaxBy(_ => _.Age);
Console.WriteLine($"\tMax : {maxAgePerson}");

var minAgePerson = People.MinBy(_ => _.Age);
Console.WriteLine($"\tMin : {minAgePerson}");

最大、最小の年齢に合致した最初の要素を返してくれます。 なんで今までなかったのか不思議ですが、ラクに取得できるようになったので嬉しいですね。

Max : Person { Name = Ichiro, Age = 47 }
Min : Person { Name = Goro, Age = 35 }

MaxとFirstの合わせ技 (.NET 5以前)

LINQでパッと思い付くのはこれでしょうか。Max()で値を取得して、その値を保持している最初の要素をFirst()で取得。

var maxAge = People.Max(_ => _.Age);
var maxAgePerson = People.FirstOrDefault(_ => _.Age == maxAge);
Console.WriteLine($"\tMax : {maxAgePerson}");

var minAge = People.Min(_ => _.Age);
var minAgePerson = People.FirstOrDefault(_ => _.Age == minAge);
Console.WriteLine($"\tMin : {minAgePerson}");

Aggregateで代用 (.NET 5以前)

集計処理をしてくれるAggregateを使用して実現できます。
xに大きい方の値を保持していき、各要素yとの比較を繰り返していきます。 今回はMaxBy/MinByに合わせて最初の要素を得るために「>=」としていますが、 最後の要素が欲しいということであれば「>」にすればOK。

var maxAgePerson = People.Aggregate((x, y) => x.Age >= y.Age ? x : y);
Console.WriteLine($"\tMax : {maxAgePerson}");

var minAgePerson = People.Aggregate((x, y) => x.Age <= y.Age ? x : y);
Console.WriteLine($"\tMin : {minAgePerson}");

拡張メソッド (.NET 5以前)

何度もAggregateを呼ぶことになるなら拡張メソッドを用意しておけばOK。

public static class LinqExtension
{
    public static T MinBy<T, U>(this IEnumerable<T> source, Func<T, U> func) where U : IComparable<U>
        => source.Aggregate((x, y) => func(x).CompareTo(func(y)) <= 0 ? x : y);

    public static T MaxBy<T, U>(this IEnumerable<T> source, Func<T, U> func) where U : IComparable<U>
        => source.Aggregate((x, y) => func(x).CompareTo(func(y)) >= 0 ? x : y);
}

呼び方は.NET 6のMaxBy()と全く同じように書けます。

var maxAgePerson = People.MaxBy(_ => _.Age);
Console.WriteLine($"\tMax : {maxAgePerson}");

var minAgePerson = People.MinBy(_ => _.Age);
Console.WriteLine($"\tMin : {minAgePerson}");

全体ソース

全体ソースを貼っておきます。 .NET 6 はmainメソッドを書く必要なくなりましたね。 .NET 5 以前のソースは言語バージョンによっては動かない書き方もしてますが、 そのままコピペしてvscodeのCode Runnerで実行できます。

.NET 6

Console.WriteLine($"Main() Start");

MaxBySample.Test1();

Console.WriteLine($"Main() End");

public record Person(string Name, int Age);

internal static class MaxBySample
{
    private static List<Person> People => new List<Person>()
    {
        new Person(Name: "Ichiro", Age: 47),
        new Person("Jiro", 47),
        new Person("Saburo", 46),
        new Person("Siro", 41),
        new Person("Goro", 35),
        new Person("Rokuro", 35),
    };

    public static void Test1()
    {
        Console.WriteLine($"*** MaxBy ***");

        var maxAgePerson = People.MaxBy(_ => _.Age);
        Console.WriteLine($"\tMax : {maxAgePerson}");
        
        var minAgePerson = People.MinBy(_ => _.Age);
        Console.WriteLine($"\tMin : {minAgePerson}");
    }
}

.NET 5 以前

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine($"Main() Start");

        MaxBySample.Test2();
        MaxBySample.Test3();
        MaxBySample.Test4();

        Console.WriteLine($"Main() End");
    }
}

public class Person
{
    public string Name {get; set;}
    public int Age {get; set;}

    public override string ToString()
        => $"Person {{ Name = {this.Name}, Age = {this.Age} }} ";
}

internal static class MaxBySample
{
    private static List<Person> People => new List<Person>()
    {
        new Person() {Name = "Ichiro", Age = 47},
        new Person() {Name = "Jiro", Age = 47},
        new Person() {Name = "Saburo", Age = 46},
        new Person() {Name = "Siro", Age = 41},
        new Person() {Name = "Goro", Age = 35},
        new Person() {Name = "Rokuro", Age = 35},
    };

    public static void Test2()
    {
        Console.WriteLine($"*** Max & First ***");

        var maxAge = People.Max(_ => _.Age);
        var maxAgePerson = People.FirstOrDefault(_ => _.Age == maxAge);
        Console.WriteLine($"\tMax : {maxAgePerson}");
        
        var minAge = People.Min(_ => _.Age);
        var minAgePerson = People.FirstOrDefault(_ => _.Age == minAge);
        Console.WriteLine($"\tMin : {minAgePerson}");
    }

    public static void Test3()
    {
        Console.WriteLine($"*** Aggregate ***");
        
        var maxAgePerson = People.Aggregate((x, y) => x.Age >= y.Age ? x : y);
        Console.WriteLine($"\tMax : {maxAgePerson}");

        var minAgePerson = People.Aggregate((x, y) => x.Age <= y.Age ? x : y);
        Console.WriteLine($"\tMin : {minAgePerson}");
    }

    public static void Test4()
    {
        Console.WriteLine($"*** MaxByExtention ***");
        
        var maxAgePerson = People.MaxBy(_ => _.Age);
        Console.WriteLine($"\tMax : {maxAgePerson}");

        var minAgePerson = People.MinBy(_ => _.Age);
        Console.WriteLine($"\tMin : {minAgePerson}");
    }
}

public static class LinqExtension
{
    public static T MinBy<T, U>(this IEnumerable<T> source, Func<T, U> func) where U : IComparable<U>
        => source.Aggregate((x, y) => func(x).CompareTo(func(y)) <= 0 ? x : y);

    public static T MaxBy<T, U>(this IEnumerable<T> source, Func<T, U> func) where U : IComparable<U>
        => source.Aggregate((x, y) => func(x).CompareTo(func(y)) >= 0 ? x : y);
}
以上、もりもりでした。

2022年3月18日金曜日

36協定届をe-Govで届け出してみた!(2022年版)

昨年、e-Govを利用して36協定届を提出した記事を書きました。


一昨年は再提出、昨年は一発合格、そして今年はというと、、、残念ながら再提出となってしまいました。


届出書の作成


手続きから「時間外労働・休日労働に関する協定届(各事業場単位による届出)(特別条項付き)」を選択します。

昨年はここで「様式追加」により、続紙や特別条項を追加する必要があったのですが、今年は初めから追加されています。
ただ、チェックボックスもないので、嫌な予感はしていたんですよね。。。


記入後、「内容を確認」を押したところ、恐れていたことが起こりました。

そうです。
提出不要の、つまり記入していない続紙がすべて入力エラーとなったのです。

続紙エリアにカーソルをあてると、右上に×ボタンが表示され、それを押すと下記の削除確認が表示されます。

一般条項・特別条項についてそれぞれ続紙9まで、ポチポチと一つずつ削除していかなければなりません。
こんなことなら昨年のように、必要な様式を追加していく方がよかったです。


翌日、不備により返戻される


提出翌日、下記の理由で返戻されました。

(1)延長することができる時間数の1年の起算日(年月日)が未入力。
(2)特別条項の事由(臨時的に限度時間を超えて労働させることができる場合)を、具体的に記入してください。(1枚目の時間外労働をさせる必要のある具体的事由とは別の事由を記入)

(1)については、以前にも書いたように「提出前に入力チェックして教えてよ!」と、自分の不注意を棚に上げて文句を言いたくなります。さらに言い訳をさせてもらうならば、この届に限らず、e-Govは入力画面が提出書類イメージになっていることで、Webシステムとして入力しづらく、入力すべき項目の見落としにつながっているのではないかと感じています。

もちろん、入力画面=提出書類イメージであることは項目の対応が明確ですし、紙から電子申請への過渡期には有効でしょう。ですが、今後さらに普及させていくためには、「WebシステムとしてのUI」に変えていくべきではないでしょうか。

(2)については、昨年までは指摘されることはありませんでした。今年から変わったのかもしれません。


e-Govを使い始めて約4年、このブログでも多くの記事を書いてきました。
2020年秋のリニューアルでかなり使いやすくなったものの、まだまだアップデートしてもらわなければなりません。
問い合わせフォームから意見や要望を送ることができるようなので、今回感じた点を送ってみようと思います。

またいつか、どこかで。

2022年3月13日日曜日

バ美声を使ってボイスチェンジする

こんにちは、やっまむーです。

これまで2回にわたってVTuberとなるための設定について書いてきました。

今回は、前回書ききれなかったボイスチェンジャーを使った音声の収録方法についてです。

ボイスチェンジャーを使う場合の出力

通常はマイクで取り込んだ音声をそのまま使用するので、OBS側でマイク入力を取り込む設定だけです。
しかし、ボイスチェンジャーを通す場合は入力出力が少し変わります。

ボイスチェンジャーアプリへマイク音声を入力し、そこから出力された音声をOBSに出力します。
図にすると簡単ですが、ボイスチェンジャーアプリの出力先としては、スピーカー等の出力デバイスしかありません。
また、OBS側でも取り込む音声として、スピーカー等の出力デバイス、またはマイク等の入力デバイスしか選択できません。
一応、変換後の音声をデスクトップ音声として出力し、それをOBSで取り込むこともできますが、他の音声も混じるためお勧めはできません。

そこで使用するのが、仮想オーディオデバイス(VAD)になります。
これは入出力の中継点として使うことができ、上記のボイスチェンジャーアプリとOBSの間を繋ぐことができます。

VAD(VB-Audio CABLE)のインストールと使い方

私は「VB-Audio CABLE」を使っています。 以下よりダウンロードしてインストールします。

Virtual Audio Cable

インストールが完了すると、サウンドデバイスの一覧に「Cable Input/Output」があることを確認します。


続いて、ボイスチェンジャーアプリの出力先を「Cable Input」に設定します。


次にOBS側のマイク入力を「CABLE Output」に設定します。

以上で設定完了です。

ボイスチェンジャーアプリは「バ美声 体験版」を使用しています。
実際に使ってみた感じでは、ボイスチェンジが挟まるため若干のズレが生じますが、シビアなタイミングを求めないのであれば十分な性能です。
実際に女性の声を出すには設定も必要ですが、声の出し方から練習が必要になります。
難しいですが、実際にそれっぽい声ができると楽しいです。
皆さんも、興味があれば是非試してみてください。

ではではー。

2022年3月6日日曜日

自然な翻訳。DeepL翻訳を活用すべし!


こんにちは。よっしーです。

最近、日本語表記ではなく英語表記でドキュメント作成する機会がありました。

正直、英語力がないので、翻訳サイトに頼ることになるのですが、
みなさん、翻訳サイトといえばどこを思い浮かべますか?

有名どころだと、Google翻訳?
昔からであれば、エキサイト翻訳?

いろいろな翻訳サイトがありますが、
私が今よく使っているのは「DeepL翻訳」です。

英語力がない私としては、翻訳サイトで翻訳した結果が、
本当に正しく翻訳されているのか?

という判断が出来ないので、
翻訳結果の英語を、日本語へ逆翻訳してみて、
意味が通じるかどうかで判断しています。

例えば、Google翻訳だと、

「キリンさんが好きです。でも、ゾウさんの方がもっと好きです。」

↓↓↓ 翻訳結果を日本語へ逆変換 ↓↓↓

「キリンさんが好きです。しかし、私は象がもっと好きです。」

なぜかキリンはジラフと変換されず、「さん」もキリンだけついている。。。

DeepL翻訳だと、

「キリンさんが好きです。でも、ゾウさんのほうがもっと好きです。」

↓↓↓ 翻訳結果を日本語へ逆変換 ↓↓↓

「私はキリンが好きです。でも、ゾウはもっと好きです。」

自然な感じに翻訳出来ている感じがします。

いつもGoogle翻訳とDeepL翻訳の2サイトで翻訳結果を比較して、
自然な感じに翻訳出来ている方を採用するのですが、
DeepL翻訳のほうを採用することが多いです。

また、DeepL翻訳はプラグインも用意されています。
Chrome上で英文を選択すると翻訳アイコンが表示されるようになり、


アイコンをクリックするだけで、翻訳されるので便利です。


ITに携わっていると、英文を読まなければいけない場面がよくあるかと思います。

Google翻訳を利用されている方が多いかとは思いますが、

翻訳結果がよくわからないな。と思った時は、一度DeepL翻訳も試してみてはいかがでしょう。

ではまた~。