Erlang: join two tables not on equality pattern - join

Is there a way to implement
SELECT *
FROM pattern p
JOIN tag t ON t.tag LIKE CONCAT(p.pattern, '%') AND t.type = p.type
in terms of erlang qlc on top of two ets:
[{{Pattern, Type}, Id}]
[{{Tag, Type}, Id}]
?
I. e. inequality pattern meaning Tag begins with Pattern and Type = Type.
Thanks in advance.

Pretty simple:
1> ets:new(a,[named_table]),[ets:insert(a,X) || X<-[{{"foo", bar},12},{{"baz", quux},11}]].
[true,true]
2> ets:new(b,[named_table]),[ets:insert(b,X) || X<-[{{"foobar", bar},12},{{"bazquux", quux},11},{{"fooxxx", bar},1},{{"bazbaz", baz},11}]].
[true,true,true,true]
3> qlc:e(qlc:q([{Pattern, Type1, Tag, Id1, Id2} || {{Pattern, Type1}, Id1} <- ets:table(a), {{Tag, Type2}, Id2} <- ets:table(b), Type1 =:= Type2, lists:prefix(Pattern, Tag)])).
[{"baz",quux,"bazquux",11,11},
{"foo",bar,"foobar",12,12},
{"foo",bar,"fooxxx",12,1}]

Related

Find substring in a string using start and end points from List

I have a list like List = [{0,12},{0,12},{-1,0},{0,12},{0,4},{1,2}] and a string Str = "https://www.youtube.com/watch?v=WQfdwsPao9E", now I've to find all the substrings using start and end point from list.
I want substrings to be returned in a List like ["https://www","https://www",..]
I tried using this:
C=lists:map(fun({X,Y}) -> string:sub_string(Str,X,Y) end,List)
1> List = [{0,12},{0,12},{-1,0},{0,12},{0,4},{1,2}].
[{0,12},{0,12},{-1,0},{0,12},{0,4},{1,2}]
2> Str = "https://www.youtube.com/watch?v=WQfdwsPao9E".
"https://www.youtube.com/watch?v=WQfdwsPao9E"
3> Len = length(Str).
43
4> [string:sub_string(Str,max(1,X),min(Len,Y)) || {X,Y} <- List].
["https://www.","https://www.",[],"https://www.","http",
"ht"]
5>
you may have to adjust the indexes in the string to fit exactly to your need.
[edit] It looks like I didn't interpret correctly what is the meaning of the tuple. I think it is {Fist_Char_Index, Char_Number}, or {-1,0} if no match is found. So you should use:
[string:sub_string(Str,X+1,X+Y) || {X,Y} <- List, {X,Y} =/= {-1,0}].

Fields with common names in different records

I have some records with similar fields, like this:
-define(COMMON_FIELDS, common1, common2, common3).
-record(item1, a, b, c, ?COMMON_FIELDS).
-record(item2, x, y, z, ?COMMON_FIELDS).
But later I need to write similar code for every record:
Record#item1.common1,
Record#item1.common2,
Record#item1.common3
and:
Record#item2.common1,
Record#item2.common2,
Record#item2.common3
Is there way to write one function for access to same fields in different records?
Is there way to write one function for access to same fields in
different records?
1) Pattern matching in multiple function clauses:
-module(x1).
-export([read/1]).
-define(COMMON_FIELDS, common1, common2, common3).
-record(item1, {x, ?COMMON_FIELDS}). %Note that you defined your records incorrectly.
-record(item2, {y, ?COMMON_FIELDS}).
read(#item1{common1=C1, common2=C2, common3=C3} = _Item) ->
io:format("~p, ~p, ~p~n", [C1, C2, C3]);
read(#item2{common1=C1, common2=C2, common3=C3} = _Item) ->
io:format("~p, ~p, ~p~n", [C1, C2, C3]).
...
25> c(x1).
{ok,x1}
26> rr(x1).
[item1,item2]
27> A = #item1{x=10, common1="hello", common2="world", common3="goodbye"}.
#item1{x = 10,common1 = "hello",common2 = "world",
common3 = "goodbye"}
28> B = #item2{y=20, common1="goodbye", common2="mars", common3="hello"}.
#item2{y = 20,common1 = "goodbye",common2 = "mars",
common3 = "hello"}
29> x1:read(A).
"hello", "world", "goodbye"
ok
30> x1:read(B).
"goodbye", "mars", "hello"
ok
Note the export statement--it's a list of length 1, i.e. the module exports one function. The output shows that the read() function can read records of either type.
2) A case statement:
If for some reason, by stating one function you mean one function clause, you can do this:
read(Item) ->
case Item of
#item1{common1=C1, common2=C2, common3=C3} -> true;
#item2{common1=C1, common2=C2, common3=C3} -> true
end,
io:format("~p, ~p, ~p~n", [C1, C2, C3]).
You can use exprecs parse transform from parse_transe.
-module(parse).
-compile({parse_transform, exprecs}).
-record(item1, {x, common1, common2}).
-record(item2, {y, common1, common2}).
-export_records([item1, item2]).
-export([p/0]).
f() ->
R1 = #item1{x=1, common1=foo1, common2=bar1},
R2 = #item2{y=2, common1=foo2, common2=bar2},
['#get-'(Field, Rec) || Field <- [common1, common2], Rec <- [R1, R2]].
...
1> c(parse).
{ok,parse}
2> parse:f().
[foo1,foo2,bar1,bar2]
It might make sense to factor out the common fields into a single field in each record companies containing a record with all the common data or even a tulple. Then refactor your code to do all common processing to its own function.
You still need to pattern match every top level record to get the common sub record. But somewhere you probably want to do the processing specific to each record kind and there you can already match out the common field.
-record(common, {c1, c2, c3}).
-record(item1, {a, b, c, com}).
...
process_item(#item1{a=A, b=B, c=C, com=Com}) ->
process_abc(A, B, C),
process_common(Com),
...;
process_item(#item2{x=X, y=Y ...
Data structures like this might also be a indication to use the new Map data type instead of records.

F# Avoid active pattern overwriting

I have noticed I cannot create two active patterns with the same options, but I can have two with similar ones without any warning:
let (|A|B|C|) c =
if (c = 'a') then A
else if (c = 'b') then B
else C
let (|A|B|D|) c =
if (c = '1') then A
else if (c = '2') then B
else D
So when matching this way:
let check myvar =
match myvar with
| A -> printf "match A\n"
| n -> printf "match other %A\n" n
This happens:
check 'x' // match other 'x'
check 'a' // match other 'a' !!
check '1' // match A
I am a bit concerned of overwriting existing active pattern options inadvertently, for example in situations where the same word can appear in different patterns because different semantic contexts, like (|Direct|Indirect|) (route) and (|Alternating|Direct|) (current).
How can I avoid this situations?
I agree that shadowing of active patterns can be tricky - though it is the same problem that you get with discriminated union cases and record labels in F#. In case of types, you can always include the type name to resolve the ambiguity.
In case of active patterns, you can put them in modules - for example Pat1 and Pat2:
module Pat1 =
let (|A|B|C|) c =
if (c = 'a') then A
else if (c = 'b') then B
else C
module Pat2 =
let (|A|B|D|) c =
if (c = '1') then A
else if (c = '2') then B
else D
So, in your code, you can then use fully qualified name like Pat1.A or Pat2.A:
let check myvar =
match myvar with
| Pat1.A -> printf "match A\n"
| n -> printf "match other %A\n" n
I think your concerns apply to shadowing in general and not just active patterns. How often will you define two active patterns whose parameters and return values are the same and have overlapping case names? Generally, types mitigate potential shadowing problems. Along these lines, type annotations are your friend.

query mnesia data by where with 'or'

SQL:
select account from y_account where id>5
Mnesia qlc:
F = fun() ->
Q = qlc:q([E#y_account.account || E <- mnesia:table(y_account), E#y_account.id>5]),
qlc:e(Q)
end,
mnesia:transaction(F).
I can select data in mnesia like this.
But how to select data by where containing 'or', like this SQL:
select account from y_account where id>5 or name='joe'
Thanks,
Best regards
I didn't check if there is a more efficient way, but you could replace
E#y_account.id>5 by (E#y_account.id>5) orelse (E#y_account.name == "joe")
Use operator or:
F = fun() ->
Q = qlc:q([E#y_account.account ||
E <- mnesia:table(y_account), (E#y_account.id > 5) or (E#y_account.name == "joe")]),
qlc:e(Q)
end,
mnesia:transaction(F).

Matching tuples with don't-care variables in Erlang

I am looking for a way to find tuples in a list in Erlang using a partial tuple, similarly to functors matching in Prolog. For example, I would like to following code to return true:
member({pos, _, _}, [..., {pos, 1, 2}, ...])
This code does not work right away because of the following error:
variable '_' is unbound
Is there a brief way to achieve the same effect?
For simple cases it's better to use already mentioned lists:keymember/3. But if you really need member function you can implement it yourself like this:
member(_, []) ->
false;
member(Pred, [E | List]) ->
case Pred(E) of
true ->
true;
false ->
member(Pred, List)
end.
Example:
>>> member(fun ({pos, _, 2}) -> true; (_) -> false end, [..., {pos, 1, 2}, ...]).
Use lists:keymember/3 instead.
You can do it with a macro using a list comprehension:
-define(member(A,B), length([0 || A <- B])>0).
?member({pos, _, _}, [{width, 17, 42}, {pos, 1, 2}, totally_irrelevant]).
It is not very efficient (it runs through the whole list) but it is the closest I can think to the original syntax.
If you want to actually extract the elements that match you just remove 'length' and add a variable:
-define(filter(A,B), [_E || A =_E <- B]).
You could do it using list comprehension:
Matches = [ Match || {Prefix, _, _} = Match <- ZeList, Prefix == pos].
Another possibility would be to do what match specs do and use the atom '_' instead of a raw _. Then, you could write a function similar to the following:
member(X, List) when is_tuple(X), is_list(List) ->
member2(X, List).
% non-exported helper functions:
member2(_, []) ->
false;
member2(X, [H|T]) when not is_tuple(H); size(X) =/= size(H) ->
member2(X, T);
member2(X, [H|T]) ->
case is_match(tuple_to_list(X), tuple_to_list(H)) of
true -> true;
false -> member2(X, T)
end.
is_match([], []) ->
true;
is_match(['_'|T1], [_|T2]) ->
is_match(T1, T2);
is_match([H|T1], [H|T2]) ->
is_match(T1, T2);
is_match(_, _) ->
false.
Then, your call would now be:
member({pos, '_', '_'}, [..., {pos, 1, 2}, ...])
This wouldn't let you match patterns like {A, A, '_'} (checking where the first two elements are identical), but if you don't need variables this should work.
You could also extend it to use variables using a similar syntax to match specs ('$1', '$2', etc) with a bit more work -- add a third parameter to is_match with the variable bindings you've seen so far, then write function clauses for them similar to the clause for '_'.
Granted, this won't be the fastest method. With the caveat that I haven't actually measured, I expect using the pattern matching in the language using a fun will give much better performance, although it does make the call site a bit more verbose. It's a trade-off you'll have to consider.
May use ets:match:
6> ets:match(T, '$1'). % Matches every object in the table
[[{rufsen,dog,7}],[{brunte,horse,5}],[{ludde,dog,5}]]
7> ets:match(T, {'_',dog,'$1'}).
[[7],[5]]
8> ets:match(T, {'_',cow,'$1'}).
[]

Resources