Qqwy

Qqwy

TypeCheck Core Team

How to partially match a string in ETS' match specs?

I am working on a small hobby project which uses ETS/(Am)nesia to learn more about how these systems work.

One thing I am struggling with, is the following:

A user might want to look up records by entering a postal code. Here in the Netherlands, postal codes have the format 1234AB that is, four (base-10) digits followed by two (always capital) letters. However, I want to allow users to be able to find all records having the postal code “1234AB”, “1234AC”, “1234DH”, etc… if they only enter “1234”. In more formal terms: I want users to find all postal codes that contain the prefix they entered.

In SQL this can be done by using a LIKE operation: SELECT * from `myTable` where `postalcode` LIKE '1234%'.
I was wondering if (how) something like this can be done using ETS’ Match Specs.

Any help would be greatly appreciated :blush:

Most Liked

sasajuric

sasajuric

Author of Elixir In Action

AFAIK, matching a binary prefix is not supported with matchspecs. A couple of options I see:

  1. Consider splitting postal code into two fields - the integer part and the letter suffiix. Then you could match on the exact integer part, since matching the exact binary value is supported with matchspecs.
  2. Use charlists instead for the postal code, because you can match the head of a charlist, which allows you to select arbitrary prefix.
  3. You could hack with comparison operators >= and < to test whether a value is greater than or equal to “12345” and less than “12346”. As far as I can tell, that might work.
  4. Iterate through table records, fetch the postal code for each record, then if the code matches the required prefix fetch the desired fields.

To test what can work with matchspecs and what isn’t supported, you can play with :ets.fun2ms from the iex shell:

iex(1)> :ets.fun2ms(fn({key, "12345"} = el) -> key end)
[{{:"$1", "12345"}, [], [:"$1"]}]

iex(2)> :ets.fun2ms(fn({key, "12345" <> _} = el) -> key end)
Error: fun head contains bit syntax matching of variable '_', which cannot be translated into match_spec
saleyn

saleyn

A bit late with this answer, but I ran into the same problem and came up with the following solution:

defmodule Matcher do
  def match_prefix(table, part) when is_binary(part) do
    prefix = String.downcase(part) |> String.to_charlist() |> to_improper_list()
    :ets.select(table, [{{prefix, :_}, [], [:"$_"]}])
  end

  defp to_improper_list([]), do: :_   # <--- this is the main trick that causes partial matching
  defp to_improper_list([h|t]), do: [h|to_improper_list(t)]
end

1> :ets.new(:t, [:public, :named_table, :ordered_set])
2> :ets.insert(:t, [{~c"1234AB", 1}, {~c"1234AC", 2}, {~c"2345BB", 3}])
true
3> Matcher.match_prefix(:t, "1234")
[{~c"1234AB", 1}, {~c"1234AC", 2}]

Where Next?

Popular in Questions Top

vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New

Other popular topics Top

KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36654 110
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44532 311
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

We're in Beta

About us Mission Statement