ChatGPT で elixir を学ぶ　（その6）text ファイルの update

こちらの記事の続きです。
[ChatGPT で elixir を学ぶ　（その5）text ファイルの read](https://qiita.com/ekzemplaro/items/6cab9f3f96f1b31db52d)

>辞書に変換してから処理を行います。

## Python のプログラム

```py:text_update.py
#! /usr/bin/python
#
#	update/text_update.py
#
#					Mar/07/2024
import	sys
import	datetime
#
# ---------------------------------------------------------------
def dict_update_proc(dict_in,id,population):
	key = str(id)
	if key in dict_in:
		dict_in[key]['population'] = population
		date_mod = datetime.date.today()
		dict_in[key]['date_mod'] = '%s' % date_mod
#
	return	dict_in
#
# ---------------------------------------------------------------
def text_write_proc(file_out,dict_aa):
#
	fp_out = open(file_out,mode='w', encoding='utf-8')
	for key in dict_aa.keys():
		unit = dict_aa[key]
		str_out = key + "\t" + str(unit['name']) + "\t"
		str_out += "%d\t" % unit['population']
		str_out += unit['date_mod'] + "\n"
		fp_out.write(str_out)
	fp_out.close()
# ---------------------------------------------------------------
def text_read_proc(file_in):
#
	fp_in = open(file_in,encoding='utf-8')
	lines = fp_in.readlines()
	fp_in.close()
#
	dict_aa = {}
	for line in lines:
		if (5 < len(line)):
			cols= line[:-1].split('\t')
			if (3 < len(cols)):
				try:
					if (cols[0][0] == "t"):
						dict_unit = {'name': cols[1], \
			'population':int (cols[2]),'date_mod':cols[3]}
						dict_aa[cols[0]] = dict_unit
				except:
					sys.stderr.write \
				("*** error *** %s ***\n" % file_in)
					sys.stderr.write \
				("*** %s ***\n" % line)
#
	return	dict_aa
# ---------------------------------------------------------------
#
sys.stderr.write("*** 開始 ***\n")
#
file_in = sys.argv[1]
id_in = sys.argv[2]
population_in = int(sys.argv[3])
print("%s\t%d" % (id_in, population_in))

dict_aa = text_read_proc(file_in)

dict_bb=dict_update_proc(dict_aa,id_in,population_in)

text_write_proc(file_in,dict_bb)
#
sys.stderr.write("*** 終了 ***\n")
# ---------------------------------------------------------------
```

実行結果

```text
$ ./text_update.py cities.txt t2387 76182500
*** 開始 ***
t2387	76182500
*** 終了 ***
```

## ChatGPT が作成したプログラム

```exs:uch01.exs
defmodule TextUpdate do
  defmodule Functions do
    def dict_update_proc(dict_in, id, population) do
      key = Integer.to_string(id)
      if key in dict_in do
        updated_date_mod = Date.utc_today()
        dict_in
        |> Map.update!(key, fn unit ->
          Map.put(unit, "population", population)
          |> Map.put("date_mod", "#{updated_date_mod}")
        end)
      else
        dict_in
      end
    end

    def text_write_proc(file_out, dict_aa) do
      File.write!(file_out, Enum.map(dict_aa, fn {key, unit} ->
        str_out = "#{key}\t#{unit["name"]}\t"
        str_out <> "#{unit["population"]}\t#{unit["date_mod"]}\n"
      end) |> Enum.join())
    end

    def text_read_proc(file_in) do
      File.read!(file_in)
      |> String.split("\n", trim: true)
      |> Enum.reduce(%{}, fn line, dict_aa ->
        cols = String.split(line, "\t")
        if length(cols) > 3 && String.starts_with?(hd(cols), "t") do
          try do
            dict_unit = %{
              "name" => List.first(Enum.drop(cols, 1)),
              "population" => String.to_integer(Enum.at(cols, 2)),
              "date_mod" => Enum.at(cols, 3)
            }
            Map.put(dict_aa, hd(cols), dict_unit)
          rescue
            _ -> 
              IO.stderr |> IO.puts("*** error *** #{file_in} ***")
              IO.stderr |> IO.puts("*** #{line} ***")
              dict_aa
          end
        else
          dict_aa
        end
      end)
    end
  end

  def run([file_in, id_in, population_in]) do
    IO.puts("#{id_in}\t#{String.to_integer(population_in)}")
    dict_aa = Functions.text_read_proc(file_in)
    dict_bb = Functions.dict_update_proc(dict_aa, String.to_integer(id_in), String.to_integer(population_in))
    Functions.text_write_proc(file_in, dict_bb)
  end
end

TextUpdate.run(System.argv())
```

実行結果

```text
$ elixir uch01.exs cities.txt t2382 18234500
t2382	18234500
** (ArgumentError) errors were found at the given arguments:

  * 1st argument: not a textual representation of an integer

    :erlang.binary_to_integer("t2382")
    uch01.exs:53: TextUpdate.run/1
    (elixir 1.14.0) lib/code.ex:1245: Code.require_file/2
```

## Gemini が作成したプログラム

```exs:uge01.exs
defmodule TextUpdate do

  # Function to update a dictionary entry based on ID and population
  def dict_update_proc(dict_in, id, population) do
    case Map.get(dict_in, id) do
      nil -> dict_in
      _ ->
        updated_value = %{
          name: Map.get(dict_in, id)["name"],
          population: population,
          date_mod: Date.utc().to_string()
        }
        Map.put(dict_in, id, updated_value)
    end
  end

  # Function to write a dictionary to a text file
  def text_write_proc(file_out, dict_aa) do
    File.open!(file_out, [:write, :encode => "utf-8"]) |>
      Enum.each(dict_aa, fn {key, unit} ->
        str_out = "#{key}\t#{unit["name"]}\t#{unit["population"]}\t#{unit["date_mod"]}\n"
        IO.write(str_out)
      end) |>
      File.close()
  end

  # Function to read a text file into a dictionary
  def text_read_proc(file_in) do
    File.stream!(file_in, [:read, :encode => "utf-8"]) |>
      Enum.reduce(%{}, fn line, dict ->
        if String.length(line) > 5 do
          [_, name, population_str, date_mod] = String.split(line, "\t", trim: true)
          try do
            population = Integer.parse!(population_str)
            if String.starts_with?(key, "t") do
              dict = Map.put(dict, key, %{
                name: name,
                population: population,
                date_mod: date_mod
              })
            end
            dict
          rescue
            IO.stderr(:write, "*** error *** #{file_in} ***\n")
            IO.stderr(:write, "*** #{line} ***\n")
            dict
          end
        else
          dict
        end
      end)
  end

  def main(args) do
    IO.stderr(:write, "*** 開始 ***\n")

    [file_in, id_in, population_in_str] = args
    id_in = String.to_integer(id_in)
    population_in = String.to_integer(population_in_str)

    IO.puts("#{id_in}\t#{population_in}")

    dict_aa = text_read_proc(file_in)
    dict_bb = dict_update_proc(dict_aa, id_in, population_in)
    text_write_proc(file_in, dict_bb)

    IO.stderr(:write, "*** 終了 ***\n")
  end
end

TextUpdate.main(Application.get_argument(:script, []))
```

実行結果

```text
$ elixir uge01.exs cities.txt t2384 82134500
** (SyntaxError) uge01.exs:19:43: syntax error before: '=>'
    |
 19 |     File.open!(file_out, [:write, :encode => "utf-8"]) |>
    |                                           ^
    (elixir 1.14.0) lib/code.ex:1245: Code.require_file/2
```

## 私が作成したプログラム

```exs:text_update.exs
# ------------------------------------------------------------------
#
#	text_update.exs
#
#						Mar/05/2024
# ------------------------------------------------------------------
defmodule MyModule do
# ------------------------------------------------------------------
    def dict_update_proc(dict_in, key, population) do
#	IO.inspect(key)
#	IO.inspect(dict_in)
      if Map.has_key?(dict_in,key) do
        IO.puts :stderr,"*** key exist ***"
        updated_date_mod = Date.utc_today()
        IO.puts :stderr,updated_date_mod
        dict_in
        |> Map.update!(key, fn unit ->
          Map.put(unit, :population, population)
          |> Map.put(:date_mod, "#{updated_date_mod}")
        end)
      else
        IO.puts :stderr,"*** key not exist ***"
        dict_in
      end
    end

# ------------------------------------------------------------------
  def text_read_proc(file_in) do
{:ok, file} = File.open(file_in, [:read, :utf8])
contents = IO.read(file,:eof)
File.close(file)
lines = String.split(contents,["\n"])
# IO.puts(length(lines))

lines_bb = Enum.filter(lines, fn x -> cols = String.split(x, "\t", trim: true)
		3 < length(cols) end)

list_aa = Enum.map(lines_bb, fn x -> cols = String.split(x, "\t", trim: true)
	[key,name,population_str,date_mod] = cols
	population = String.to_integer(population_str)
	dict_unit = %{name: name,population: population, date_mod: date_mod}
		[key, dict_unit]
		end)
		
        Enum.reduce(list_aa, %{}, fn [key, value], acc ->
		Map.put(acc, key, value)
		end)
  end

# ------------------------------------------------------------------
  def text_write_proc(file_out,dict_aa) do
    {:ok, fp_out} = File.open(file_out, [:write, :utf8])
    ll = Map.keys dict_aa
    Enum.each(ll, fn(s) ->
	str_out =  to_string(s) <> "\t" <>  dict_aa[s].name  <> "\t" <> Integer.to_string(dict_aa[s].population) <> "\t" <> dict_aa[s].date_mod <> "\n"
	IO.write(fp_out,str_out)
	end)
    File.close(fp_out)
  end


# ------------------------------------------------------------------
end
# ------------------------------------------------------------------
IO.puts :stderr,"*** 開始 ***"
[file_in, id_in, population_in_str]  = System.argv()
IO.puts :stderr,file_in

population_in = String.to_integer(population_in_str)

IO.puts("#{id_in}\t#{population_in}")

dict_aa = MyModule.text_read_proc(file_in)

dict_bb = MyModule.dict_update_proc(dict_aa, id_in, population_in)
# IO.inspect(dict_bb)

MyModule.text_write_proc(file_in, dict_bb)


IO.puts :stderr,"*** 終了 ***"
# ------------------------------------------------------------------
```

実行結果

```text
$ elixir text_update.exs cities.txt t2388 19534600
*** 開始 ***
cities.txt
t2388	19534600
*** key exist ***
2024-03-07
*** 終了 ***
```