新普金娱乐网址


Objective-C 数据集合

数学人为智能一:Al学习路线

elixir 入门笔记

  • 二月 04, 2019
  • 数学
  • 没有评论

安装

2014年6月15日3,5070

MAC 平台用 brew 安装

brew update
brew install elixir

假使没有 erlang 环境,上面的一声令下会自定安装 erlang 的环境。

Description

Longge的数学成就万分好,并且她分外愿意挑衅高难度的数学难题。现在题材来了:给定一个整数N,你需需求出∑gcd(i,
N)(1<=i <=N)。

主导数据类型

iex> 1          # integer
iex> 0x1F       # integer
iex> 1.0        # float
iex> true       # boolean
iex> :atom      # atom / symbol
iex> "elixir"   # string
iex> [1, 2, 3]  # list
iex> {1, 2, 3}  # tuple

Input

一个平头,为N。

数学运算

iex> 1 / 2
1 / 2
0.5

/ 总是回到浮点数,如若要求整数运算,使用 div 和 rem 函数

iex> div(1, 2)
div(1, 2)
0
iex> rem(1, 2)
rem(1, 2)
1

Output

一个平头,为所求的答案。

二进制,八进制,十六进制表示方法

iex> 0b10000
0b10000
16
iex> 0o20
0o20
16
iex> 0x10
0x10
16

Sample Input

6

原子

原子是一种常量,变量名就是它的值。有2种写法:

  1. :原子名
  2. :”原子名”

Sample Output

15

列表

  1. 列表中能够分包自由数据类型

    iex> [1, 1.2, true, "hello"]
    [1, 1.2, true, "hello"]
    [1, 1.2, true, "hello"]
    
  2. 列表可以透过 ++/– 来拼接

    iex> [1, 2, true] ++ [1, 3, false]
    [1, 2, true] ++ [1, 3, false]
    [1, 2, true, 1, 3, false]
    
    iex> [1, 2, true, 2, false] -- [1, 3, false, 2]
    [1, 2, true, 2, false] -- [1, 3, false, 2]
    [true, 2]
    
  3. 能够通过 hd/1 tl/1 函数来收获尾部和底部以外的一部分

    iex> hd([1, 2, true])
    hd([1, 2, true])
    1
    
    iex> tl([1, 2, true])
    tl([1, 2, true])
    [2, true]
    
  4. 对一个空列表执行 hd/1 和 tl/1 会报错

    iex> hd([])
    hd([])
    ** (ArgumentError) argument error
        :erlang.hd([])
    
    iex> tl([])
    tl([])
    ** (ArgumentError) argument error
        :erlang.tl([])
    

HINT

【数据范围】
对于60%的数据,0<N<=2^16。
对于100%的数据,0<N<=2^32。

列表和元组差异

  1. 列表是以链表格局在内存存储的,元组是在内存中总是存储的。
  2. 列表后置拼接操作便捷,前置拼接操作慢
    前置拼接时修改了原列表的结尾一个要素,所以会重建总体列表
  3. 函数的重临值一般用元组来保存

题解

题材中必要出∑gcd(i,N)(1<=i<=N)。

枚举n的约数k,令s(k)为满足gcd(m,n)=k,(1<=m<=n)m的个数,则ans=sigma(k*s(k))
(k为n的约数)

因为gcd(m,n)=k,所以gcd(m/k,n/k)=1,于是s(k)=euler(n/k)

phi能够在根号的小时内求出

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #define ll long long
 7 using namespace std;
 8 
 9 ll n,ans;
10 int m;
11 
12 ll phi(ll x)
13 {
14     ll t=x;
15     for(ll i=2;i<=m;i++)
16         if(x%i==0)
17         {
18             t=t/i*(i-1);
19             while(x%i==0)x/=i;
20         }
21     if(x>1)t=t/x*(x-1);
22     return t;
23 }
24 int main()
25 {
26     scanf("%lld",&n);
27     m=sqrt(n);
28     for(int i=1;i<=m;i++)
29         if(n%i==0)
30         {
31             ans+=(ll)i*phi(n/i);
32             if(i*i<n)ans+=(ll)(n/i)*phi(i);  
33         }
34     printf("%lld",ans);
35 }

 

字符串和字符列表

  1. 双引号包裹的是字符串: 字符串中贮存的是 byte
  2. 单引号包裹的是字符列表: 字符列表中储存的是种种字符的 codepoint

大旨运算符

  1. 算术运算 + – * / div/2 rem/2
  2. 列表拼接 ++ –
  3. 字符串拼接 <>

    iex> "foo" <> "bar"
    "foo" <> "bar"
    "foobar"
    
  4. 布尔运算符

    • or and not 那3个运算符只接受布尔值作为第三个参数

      iex> true or 1
      true or 1
      true
      
      iex> 1 or true
      1 or true
      ** (ArgumentError) argument error: 1
      
    • || && ! 那3个运算符能够承受非布尔值作为首个参数

      iex> 1 || true
      1 || true
      1
      
      iex> true || 1
      true || 1
      true
      
  5. 正如运算符
    = ! = !== <= >= < >

    • = != !== 相比较,后者的自我批评尤其严格

      iex> 1 == 1.0
      1 == 1.0
      true
      
      iex> 1 === 1.0
      1 === 1.0
      false
      
      iex> 1 != 1.0
      1 != 1.0
      false
      
      iex> 1 !== 1.0
      1 !== 1.0
      true
      
    • 今非昔比数据类型之间也足以比较大小

      iex> 1 < "hello"
      1 < "hello"
      true
      
      iex> 1 > "hello"
      1 > "hello"
      false
      
      iex> 1 < [1, 2]
      1 < [1, 2]
      true
      
      iex> "hello" < [1, 2]
      "hello" < [1, 2]
      false
      

      不等数据类型之间的默许的逐一如下:

      number < atom < reference < functions < port < pid < tuple < maps < list < bitstring
      

方式匹配

  1. elixir 中 = 是格局匹配运算符
  2. 可以给list 的 head 和 tail 赋值

    iex> [h|t]=[1,2,3]
    [1, 2, 3]
    iex> h
    1
    iex> t
    [2, 3]
    

支配语句

case

iex> case {1, 2, 3} do
...>   {4, 5, 6} ->
...>     "This clause won't match"
...>   {1, x, 3} ->
...>     "This clause will match and bind x to 2 in this clause"
...>   _ ->
...>     "This clause would match any value"
...> end

case的原则中可以进入判断的表明式,比如上边的 (when x > 0)

iex> case {1, 2, 3} do
...>   {1, x, 3} when x > 0 ->
...>     "Will match"
...>   _ ->
...>     "Won't match"
...> end

cond

iex> cond do
...>   2 + 2 == 5 ->
...>     "This will not be true"
...>   2 * 2 == 3 ->
...>     "Nor this"
...>   1 + 1 == 2 ->
...>     "But this will"
...>   3 + 3 == 6 ->
...>     "But this will too"
...> end
"But this will"

只会举办第三个门当户对上的道岔

if/unless

iex> if nil do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

unless 和 if 相反,条件为false时才实施

iex> unless true do
...>   "This won't be seen"
...> else
...>   "This will"
...> end
"This will"

do

do 语句快有2种写法:

iex> if true do
...> "this is true"
...> else
...> "this is false"
...> end

OR

iex> if true, do: ("this is true"), else: ("this is false")

键值列表-图-字典

键值列表

iex> l = [{:a, 1},{:b, 2}]
[a: 1, b: 2]
iex> l[:a]
1

iex> l[:b]
2

键值列表还有另一种概念方式:(注意 a: 和 1 之间必须有个空格)

iex> l = [a: 1, b: 2]
[a: 1, b: 2]

键值列表2个特色:

  1. 有序
  2. key 可以另行,重复时,优先取排在前面的key

    iex> l = [a: 3] ++ l;
    [a: 3, a: 1, b: 2]
    iex> l
    [a: 3, a: 1, b: 2]
    iex> l[:a]
    3

数学,图的2个特点:

  1. 图中的key是无序的
  2. 图的key可以是自由档次

    iex> map = %{:a => 1, 2 => :b}
    %{2 => :b, :a => 1}

图匹配时,只要 = 左侧包括右边的值就能匹配上

iex> %{} = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}

iex> %{:a => 1, 2 => :b} = %{}
    ** (MatchError) no match of right hand side value: %{}

iex> %{:a => 1} = %{:a => 1, 2 => :b}
%{2 => :b, :a => 1}

iex> %{:a => 1, :c => 2} = %{:a => 1, 2 => :b}
   ** (MatchError) no match of right hand side value: %{2 => :b, :a => 1}

修改图中的值可以用以下的办法:

iex> %{map | 2 => :c}
%{2 => :c, :a => 1}

字典

上述的 键值列表 和 图 都是 字典 ,它们都落到实处了 Dict 接口。
此模块现在一度 deprecated

模块和函数定义

模块和函数定义形式

defmodule Math do
  def sum(a, b) do
    do_sum(a, b)
  end

  defp do_sum(a, b) do
    a + b
  end
end

Math.sum(1, 2)    #=> 3
Math.do_sum(1, 2) #=> ** (UndefinedFunctionError)

函数中的卫兵表明式

defmodule Math do
  def zero?(0) do
    true
  end

  def zero?(x) when is_number(x) do
    false
  end
end

Math.zero?(0)  #=> true
Math.zero?(1)  #=> false

Math.zero?([1,2,3])
#=> ** (FunctionClauseError)

默许参数

defmodule Concat do
  def join(a, b, sep \\ " ") do
    a <> sep <> b
  end
end

IO.puts Concat.join("Hello", "world")      #=> Hello world
IO.puts Concat.join("Hello", "world", "_") #=> Hello_world

枚举类型和流

枚举类型

枚举类型提供了大批量函数来对列表进行操作

iex> Enum.sum([1,2,3])
6
iex> Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.reduce(1..3, 0, &+/2)
6
iex> Enum.filter(1..3, &(rem(&1, 2) != 0))
[1, 3]

枚举操作都是积极的,比如如下的操作:

iex> odd? = &(rem(&1, 2) != 0)
#Function<6.54118792/1 in :erl_eval.expr/5>

iex> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
7500000000

上述每步的操作(Enum.map, Enum.filter)都会时有暴发一个新的列表,这就是
积极 的意思。

和方面的枚举类型对应,流的处理是 懒惰 的,比如:

iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
7500000000

表面上看,和枚举类型的处理一样,而实在,流先创制了一名目繁多的臆想操作。然后仅当大家把它传递给Enum模块,它才会被调用。

iex> stream = 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
#Stream<[enum: 1..100000,
 funs: [#Function<23.27730995/1 in Stream.map/2>,
  #Function<8.27730995/1 in Stream.filter/2>]]>
iex> Enum.sum(stream)   <== 这里才开始执行
7500000000

进程

elixir中经过都是轻量级的,所以利用时毫不太在意进度的数量。

  1. 派生的长河执行完自动终止自己

    iex> pid = spawn fn -> 1 + 2 end
    #PID<0.62.0>
    iex> Process.alive?(pid)
    false
    
  2. 发送和收取音讯
    上面示例中是给协调发送了一条信息,可以经过 flush/1
    函数刷新信息,刷新四回以后就

    iex> send self(), {:hello, "world"}
    {:hello, "world"}
    iex> flush
    {:hello, "world"}
    :ok
    iex> flush
    :ok
    

    也足以通过 receive/1 函数来接收

    iex> send self(), {:hello, "world"}
    {:hello, "world"}
    iex> receive do
    ...> {:hi, msg} -> msg
    ...> {:hello, msg} -> msg
    ...> end
    "world"
    

    receive/1 函数收不到音信会阻塞,能够给它设置一个过期时间

    iex> receive do
    ...> {:hello, msg} -> msg
    ...> after
    ...> 3000 -> "timeout"
    ...> end
    "timeout"
    
  3. 进度间的一而再
    进度B连接进度A之后,进度A出现卓殊,进度B就能捕获,那样经过B就能处理进度A的不得了
    经过连接的办法很粗略,就是 spawn_link/1 函数

    iex> spawn fn -> raise "oops" end
    #PID<0.76.0>
    
    15: 18:22.804 [error] Process #PID<0.76.0> raised an exception
    ** (RuntimeError) oops
    :erlang.apply/2
    
    iex> spawn_link fn -> raise "oops" end
    ** (EXIT from #PID<0.73.0>) an exception was raised:
    ** (RuntimeError) oops
    :erlang.apply/2
    
    15: 18:31.533 [error] Process #PID<0.78.0> raised an exception
     ** (RuntimeError) oops
     :erlang.apply/2
    

    关注
    Process模块
    模块,里面提供了经过操作的函数

  4. 进程中保留境况的措施:

    defmodule KV do
      def start do
        {:ok, spawn_link(fn -> loop(%{}) end)}
      end
    
      defp loop(map) do
        receive do
          {:get, key, caller} ->
            send caller, Map.get(map, key)
            loop(map)
          {:put, key, value} ->
            loop(Map.put(map, key, value))
        end
      end
    end
    
    iex> send pid, {:put, :hello, :world}
    #PID<0.62.0>
    iex> send pid, {:get, :hello, self()}
    {:get, :hello, #PID<0.41.0>}
    iex> flush
    :world
    

    实则行使时,可以用 Agent
    模块

    来简化上边的操作。

模块属性

elixir中模块的性质紧要有3个职能:

  1. 作为一个模块的诠释,寻常附加上用户或编造机用到的音讯
  2. 用作常量
  3. 在编译时作为一个暂时的模块存储

注释

诠释时,一些常用的模块属性如下:

名称 含义
@moduledoc 为当前模块提供文档
@doc 为该属性后面的函数或宏提供文档
@behaviour (注意这个单词是英式拼法)用来注明一个OTP或用户自定义行为
@before\_compile 提供一个每当模块被编译之前执行的钩子。这使得我们可以在模块被编译之前往里面注入函数。

常量

作为常量:

defmodule MyServer do
  @my_data 14
  def first_data, do: @my_data
  @my_data 13
  def second_data, do: @my_data
end

测试方法:

iex> MyServer.first_data
14

iex> MyServer.second_data
13

暂时存储

模块中的变量只在编译时存在,所以用做临时存储,存储一些只在编译时利用的变量。
示例:

defmodule MyServer do
  @my_data 14
  def first_data, do: @my_data
  @my_data 13
  def second_data, do: @my_data
end

iex> MyServer.first_data #=> 14
iex> MyServer.second_data #=> 13

结构体

  1. 定义

    defmodule User do
      defstruct name: "harry", age: 32
    end
    
  2. 使用办法

    iex> j = %User{}
    %User{age: 32, name: "harry"}
    
    iex> j.name
    "harry"
    
    iex> j[:name]
    ** (UndefinedFunctionError) undefined function User.fetch/2
                 User.fetch(%User{age: 32, name: "harry"}, :name)
        (elixir) lib/access.ex:77: Access.get/3
    
    iex> j.__struct__
    User
    

协议

协商类似于其余语言中的接口,什么人促成了商事,何人就足以运用协议,
比如说下面的例子,Integer 和 User
结构体完成了商谈,就足以采用协议中的方法。

defmodule User do
  defstruct name: "harry", age: 32
end

defprotocol Enough do
  def enough?(data)
end

defimpl Enough, for: Integer do
  def enough?(data) do
    if data > 0 do
      true
    else
      false
    end
  end
end

defimpl Enough, for: User do
  def enough?(data) do
    if data.age > 18 do
      true
    else
      false
    end
  end
end

应用示例:

iex> Enough.enough?(11)
true
iex> Enough.enough?(0)
false

iex> u = %User{}
%User{age: 32, name: "harry"}
iex> Enough.enough?(u)
true

iex> u = %{u|age: 10}
%User{age: 10, name: "harry"}
iex> Enough.enough?(u)
false

iex> Enough.enough?("string")
 ** (Protocol.UndefinedError) protocol Enough not implemented for "string"
    iex:3: Enough.impl_for!/1
    iex:4: Enough.enough?/1

地点的 string 类型没有完结协议,所以不可能使用。
俺们在其实应用中也不会对没连串型都落实协议,为了防止现身非常,可以安装协议对负有品种的默许完毕

defprotocol Enough do
  @fallback_to_any true
  def enough?(data)
end

defimpl Enough, for: Any do
  def enough?(_), do: false
end

这般之后,如下使用就不会报错了

iex> Enough.enough?("string")
false

可怜处理

自定义杰出

自定义相当使用 defexception/1 函数,

iex> h(defexception)
The most common way to raise an exception is via raise/2:

┃ defmodule MyAppError do
┃   defexception [:message]
┃ end
┃
┃ value = [:hello]
┃
┃ raise MyAppError,
┃   message: "did not get what was expected, got: #{inspect value}"

In many cases it is more convenient to pass the expected value to raise/2 and
generate the message in the exception/1 callback:

┃ defmodule MyAppError do
┃   defexception [:message]
┃
┃   def exception(value) do
┃     msg = "did not get what was expected, got: #{inspect value}"
┃     %MyAppError{message: msg}
┃   end
┃ end
┃
┃ raise MyAppError, value

The example above shows the preferred strategy for customizing exception
messages.

非常的应用

elixir 就算提供了 try/catch/rescue/after
的结构,但是尽量不要使用那种结构,使用那种分外处理方式,会影响现有程序的拍卖流程。
elixir
的多多函数都会回去错误信号,通过信号来处理错误是推荐的方法(类似golang的错误处理),比如如下示例:

iex> case File.read "hello" do
...>   {:ok, body} -> IO.puts "got ok"
...>   {:error, body} -> IO.puts "got error"
...> end

列表速构

速构的情趣也就是从一个列表方便的转变另一个列表。

  1. 生成器

    iex> l = for n <- [1, 2, 4], do: n*n
    [1, 4, 16]
    iex> l
    [1, 4, 16]
    
  2. 过滤器

    iex> require Integer
    
    iex> for n <- 1..4, Integer.is_odd(n), do: n*n
    [1, 9]
    
  3. 二进制转化为元组

    iex> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
    <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
    
    iex> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
    [{213, 45, 132}, {64, 76, 32}, {76, 0, 0}, {234, 32, 15}]
    
  4. into

    • 剔除空格

      iex> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
      "helloworld"
      

sigils(魔法印)

sigils 也就是对已有些变量或者常量做一些标志,使之成为其他的事物。
sigils 的目的就是增进 elixir 语言的扩充性。

  1. 正则表明式中的使用

    iex> regex = ~r/foo|bar/
    ~r/foo|bar/
    
    iex> "foo" =~ regex
    true
    
    iex> "bat" =~ regex
    false
    
  2. 代表字符串,字符以及列表的示范

    iex> ~s(this is a string with "quotes")
    "this is a string with \"quotes\""
    
    iex> ~c(this is a string with "quotes")
    'this is a string with "quotes"'
    
    iex> ~w(foo bar bat)
    ["foo", "bar", "bat"]
    

    ~w 还是能进入此外的修饰符(比如:c, s, a
    分别表示字符列表,字符串,原子)

    iex> ~w(foo bar bat)a
    [:foo, :bar, :bat]
    
  3. 自定义 sigils

    iex> defmodule MySigils do
    ...> def sigil_i(string, []), do: string <> "add_sigil"
    ...> end
    
    iex> import MySigils
    iex> ~i("123")
    

相关文章

No Comments, Be The First!
近期评论
    分类目录
    功能
    网站地图xml地图