I have this table :
-record(person, {id, firstname, lastname, address}).
for example this table contains this values :
2 alen dumas paris
5 franco mocci parma
3 ali othmani london
Now I have the variable Key which contains this value 10
I want to develop a function in erlang which will modify all id of the table person
the new value of this id will be the previous value + the value of Key
mean the table person will became like this
12 alen dumas paris
15 franco mocci parma
13 ali othmani london
meaning each id will be added by 10 (is the value of Key) :(2+10) (5+10) (3+10)
I try with your code :
testmodify()->
Key=22,
[ P#person{id=P#person.id+Key} || P <- Persons ].
but I have this error in the sysntax : variable Persons is unbound
I try to resolve this problem with this code :
testmodify()->
Key=22,
[ P#person{id=P#person.id+Key} || P <- mnesia:table(person) ].
but I have this error :
1> model:testmodify().
** exception error: no function clause matching
model:'-testmodify/0-lc$^0/1-0-'({qlc_handle,
{qlc_table,
#Fun<mnesia.20.112329951>,
true,
#Fun<mnesia.21.62211129>,
#Fun<mnesia.22.75429001>,
#Fun<mnesia.23.26336897>,
#Fun<mnesia.26.62819299>,
#Fun<mnesia.25.51075493>,
#Fun<mnesia.24.47804912>,
'=:=',undefined,
no_match_spec}})
Assuming your table is stored as a list:
[ P#person{id=P#person.id+Key} || P <- Persons ].
UPDATE: For an Mnesia table, you can retrieve similar results with QLC:
-include_lib("stdlib/include/qlc.hrl").
⋮
[ P#person{id=P#person.id+Key} || P <- mnesia:table(person) ].
Note that this only gives you a list of transformed person records. To update the records, you'll probably have to remove the existing records and write the new records in a transaction, since a record with a modified key (assuming that's what id is) is treated as a different record — something like this:
mnesia:transaction(fun() ->
Old = [ P || P <- mnesia:table(person) ],
New = [ P#person{id=P#person.id+Key} || P <- Old ],
[ mnesia:delete({person, P#Person.id}) || P <- Old ],
[ mnesia:write(P) || P <- New ]
end)
You might be able to do this in a single pass with mnesia:foldr, but I don't know what happens if you issue mnesia:delete and mnesia:write inside mnesia:foldr. You might get stuck in an infinite loop (but don't quote me on that).
Related
I am trying to do a left join between two data frames in Deedle. Examples of the two data frames are below:
let workOrders =
Frame.ofColumns [
"workOrderCode" =?> series [ (20050,20050); (20051,20051); (20060,20060) ]
"workOrderDescription" =?> series [ (20050,"Door Repair"); (20051,"Lift Replacement"); (20060,"Window Cleaning") ]]
// This does not compile due to the duplicate Work Order Codes
let workOrderScores =
Frame.ofColumns [
"workOrderCode" => series [ (20050,20050); (20050,20050); (20051,20051) ]
"runTime" => series [ (20050,20100112); (20050,20100130); (20051,20100215) ]
"score" => series [ (20050,100); (20050,120); (20051,80) ]]
Frame.join JoinKind.Outer workOrders workOrderScores
The problem is that Deedle will not let me create a data frame with a non unique index and I get the following error: System.ArgumentException: Duplicate key '20050'. Duplicate keys are not allowed in the index.
Interestingly in Python/Pandas I can do the following which works perfectly. How can I reproduce this result in Deedle? I am thinking that I might have to flatten the second data frame to remove the duplicates then join and then unpivot/unstack it?
workOrders = pd.DataFrame(
{'workOrderCode': [20050, 20051, 20060],
'workOrderDescription': ['Door Repair', 'Lift Replacement', 'Window Cleaning']})
workOrderScores = pd.DataFrame(
{'workOrderCode': [20050, 20050, 20051],
'runTime': [20100112, 20100130, 20100215],
'score' : [100, 120, 80]})
pd.merge(workOrders, workOrderScores, on = 'workOrderCode', how = 'left')
# Result:
# workOrderCode workOrderDescription runTime score
#0 20050 Door Repair 20100112 100
#1 20050 Door Repair 20100130 120
#2 20051 Lift Replacement 20100215 80
#3 20060 Window Cleaning NaN NaN
This is a great question - I have to admit, there is currently no elegant way to do this with Deedle. Could you please submit an issue to GitHub to make sure we keep track of this and add some solution?
As you say, Deedle does not let you have duplicate values in the keys currently - although, your Pandas solution also does not use duplicate keys - you simply use the fact that Pandas lets you specify the column to use when joining (and I think this would be great addition to Deedle).
Here is one way to do what you wanted - but not very nice. I think using pivoting would be another option (there is a nice pivot table function in the latest source code - not yet on NuGet).
I used groupByRows and nest to turn your data frames into series grouped by the workOrderCode (each item now contains a frame with all rows that have the same work order code):
let workOrders =
Frame.ofColumns [
"workOrderCode" =?> Series.ofValues [ 20050; 20051; 20060 ]
"workOrderDescription" =?> Series.ofValues [ "Door Repair"; "Lift Replacement"; "Window Cleaning" ]]
|> Frame.groupRowsByInt "workOrderCode"
|> Frame.nest
let workOrderScores =
Frame.ofColumns [
"workOrderCode" => Series.ofValues [ 20050; 20050; 20051 ]
"runTime" => Series.ofValues [ 20100112; 20100130; 20100215 ]
"score" => Series.ofValues [ 100; 120; 80 ]]
|> Frame.groupRowsByInt "workOrderCode"
|> Frame.nest
Now we can join the two series (because their work order codes are the keys). However, then you get one or two data frames for each joined order code and there is quite a lot of work needed to outer join the rows of the two frames:
// Join the two series to align frames with the same work order code
Series.zip workOrders workOrderScores
|> Series.map(fun _ (orders, scores) ->
match orders, scores with
| OptionalValue.Present s1, OptionalValue.Present s2 ->
// There is a frame with some rows with the specified code in both
// work orders and work order scores - we return a cross product of their rows
[ for r1 in s1.Rows.Values do
for r2 in s2.Rows.Values do
// Drop workOrderCode from one series (they are the same in both)
// and append the two rows & return that as the result
yield Series.append r1 (Series.filter (fun k _ -> k <> "workOrderCode") r2) ]
|> Frame.ofRowsOrdinal
// If left or right value is missing, we just return the columns
// that are available (others will be filled with NaN)
| OptionalValue.Present s, _
| _, OptionalValue.Present s -> s)
|> Frame.unnest
|> Frame.indexRowsOrdinally
This might be slow (especially in the NuGet version). If you work on more data, please try building latest version of Deedle from sources (and if that does not help, please submit an issue - we should look into this!)
I need your help again, I am trying to understand this piece of erlang code.
Line="This is cool".
Lines = [Line || _Count <- lists:seq(1,5)].
output is
["This is cool","This is cool","This is cool","This is cool","This is cool"]
I don't understand the logic behind it printing the required number of times. What does Line || _***** means?
Since the value of Line is not changed in the right hand side of the list comprehension, the value of each element is the same, the value of Line.
The right side of the list comprehension is just determining the number of elements.
Look at this piece of code:
Line = "This is cool".
Lines = [{Line, Count} || Count <- lists:seq(1, 5)].
Here you create a list of tuples of size 2 where first element is constant and the second is taken from the source list of list comprehension. And if you remove an element from the tuple it won't change list's structure.
it can be read like this: NewListe = [Dosomething || Element <- Liste]
create a NewListe this way: for each Element of Liste, build a new element with Dosomething.
Step by step it gives Liste = lists:seq(1,5) = [1,2,3,4,5];
for each Element, just discard the value of element (it is why it is written as _Count) and
Dosomething is only send back the value "This is cool",
and the result is a list of 5 times "This is cool"
["This is cool","This is cool","This is cool","This is cool","This is cool"]
<- is called a generator; after the sign || you may have generators or filters. For example if we imagine that you have a list of different elements and want to get only the printable list items, turned to upper case, you will need a generator:
X <- ["toto",5,"Hello",atom] to get each element
a filter:
io_lib:printable_list(X) to select only the printable lists
and a transformation:
string:to_upper(X) to turn to upper case
all together you have what is expected:
1> [string:to_upper(X) || X <- ["toto",5,"Hello",atom], io_lib:printable_list(X)].
["TOTO","HELLO"]
2>
I know it's very easy to do in Python: someList[1:2]
But how do you this in Lua? That code gives me a syntax error.
{unpack(someList, from_index, to_index)}
But table indexes will be started from 1, not from from_index
The unpack function built into Lua can do this job for you:
Returns the elements from the given table.
You can also use
x, y = someList[1], someList[2]
for the same results. But this method can not be applied to varying length of lua-table.
Usage
table.unpack (list [, i [, j]])
Returns the elements from the given table. This function is equivalent to
return list[i], list[i+1], ···, list[j]
By default, i is 1 and j is #list.
A codepad link to show the working of the same.
The exact equivalent to the Python
someList = [ 'a', 'b', 'c', 'd' ]
subList = someList[1:2]
print( subList )
in Lua is
someList = { 'a', 'b', 'c' , 'd' }
subList = { unpack( someList, 2, 2 ) }
print( unpack(subList) )
The key thing is that unpack returns "multiple results" which is not a table, so to get a list (aka table) in Lua you need to "tablify" the result with { and }.
However, you cannot print a table in Lua, but you can print multiple results so to get meaningful output, you need to unpack it again.
So unlike Python which mimics multiple returns using lists, Lua truly has them.
Nb in later versions of Lua unpack becomes table.unpack
I have a table person with this record
-record(person, {id, firstname, lastname, phone}).
I want to update the phone of all records of this table
Itry with
test()->
Newphone ="216",
Update=#person{phone=Newphone} ,
Fun = fun() ->
List = mnesia:match_object(Update),
lists:foreach(fun(X) ->
mnesia:write_object(X)
end, List)
end,
mnesia:transaction(Fun).
The table person contains
12 alen dumas 97888888
15 franco mocci 55522225
13 ali othmani 44444449
I want that this table became like this :
12 alen dumas 216
15 franco mocci 216
13 ali othmani 216
I try with :
test()->
Newphone ="216",
Update=X#person{phone=Newphone, _ = '_'}
Fun = fun() ->
List = mnesia:match_object(Update),
lists:foreach(fun(X) ->
mnesia:write(X)
end, List)
end,
mnesia:transaction(Fun).
but with this code I have this error :
Variable X is unbound
this is related to this line :
Update=X#person{phone=Newphone, _ = '_'}
to resolve this probleme I do :
test()->
Newphone ="216",
Update=#person{phone=Newphone, _ = '_'}
Fun = fun() ->
List = mnesia:match_object(Update),
lists:foreach(fun(X) ->
mnesia:write(X)
end, List)
end,
mnesia:transaction(Fun).
when I test I have this message :
{atomic,ok}
but when I consult the database I find that the records are not changed
the difficulty in my code is to change all records of the table person
so change 97888888 and 55522225 and 44444449
this values should became 216
Continuing from what #legoscia has started. There are a couple of problems left with your code:
In the mnesia:match_object/1 call Update is being used as a pattern so when you set the phone field phone=NewPhone in Update you are actually saying to match_object give me all the records which have a phone of value "216". Which is not what you want.
You are writing back exactly the same record as you matched. You are not changing the record before writing it back.
A solution could be (untested):
test()->
Newphone ="216",
Match=#person{_ = '_'}, %Will match all records
Fun = fun() ->
List = mnesia:match_object(Match),
lists:foreach(fun(X) ->
%% Create new record with phone=NewPhone and write it back
Update = X#person{phone=NewPhone},
mnesia:write(Update)
end, List)
end,
mnesia:transaction(Fun).
Any fields you set in Match will limit which records you will match in match_object. For example Match = #person{phone="123",_='_'} will match all records which have phone "123".
A few things need changing here:
If you are going to use a record as a template for mnesia:match_object, you should fill in the record fields that you don't care about with the atom '_'. There is a special syntax to do that:
Update=#person{phone=Newphone, _ = '_'}
You probably don't want Newphone in there—the record that you pass to match_object should match the objects that are already in the table but should be changed, not what you want the objects to be changed to.
Which records are you trying to change? That will determine what you should pass to match_object.
The only thing you do in the transaction is reading records and writing them back unchanged. Have a look at the Records chapter of the Erlang reference manual; you probably want something like X#person{phone = Newphone} to change the phone field in X.
The function mnesia:write_object doesn't exist; you probably meant mnesia:write.
I always assumed that changing the value of k from "x" to 20 would eliminate "x". So why then in this example are we able to go back and reference "x"?
a = {}
k = "x"
a[k] = 10
print(a[k]) ---> Returns 10
print(a["x"]) ---> Returns 10
a[20] = "great"
k = 20
print(a[k]) ---> "great"
a["x"] = a["x"] + 1
print(a["x"]) --> 11
Why does that last print command work, and return 11? I thought we set k = 20. Why is "x" even in the picture?
Lua calls table what others programming languages call dictionary or hash, a table is a data structure that stores a pairs of key and value, we can not have two identical keys in a table, but we can have same values for diferent keys. So basicly what you are doing in line 2 is giving your variable "k" value "x", on line 3 you are saying that the table "a" will have an entry with value 10 which is referenced by key "x" not variable "k", variable "k" is a anddress not a value.
I hope I helped somehow.