How to merge two tables overwriting the elements which are in both? - merge

I need to merge two tables, with the contents of the second overwriting contents in the first if a given item is in both. I looked but the standard libraries don't seem to offer this. Where can I get such a function?

for k,v in pairs(second_table) do first_table[k] = v end

Here's what i came up with based on Doug Currie's answer:
function tableMerge(t1, t2)
for k,v in pairs(t2) do
if type(v) == "table" then
if type(t1[k] or false) == "table" then
tableMerge(t1[k] or {}, t2[k] or {})
else
t1[k] = v
end
else
t1[k] = v
end
end
return t1
end

Wouldn't this work properly?
function merge(t1, t2)
for k, v in pairs(t2) do
if (type(v) == "table") and (type(t1[k] or false) == "table") then
merge(t1[k], t2[k])
else
t1[k] = v
end
end
return t1
end

For numeric-index table merging:
for k,v in pairs(secondTable) do table.insert(firstTable, v) end

Doug Currie's answer is the simplest for most cases. If you need more robust merging of tables, consider using the merge() method from the Penlight library.
require 'pl'
pretty.dump(tablex.merge({a=1,b=2}, {c=3,d=4}, true))
-- {
-- a = 1,
-- d = 4,
-- c = 3,
-- b = 2
-- }

Here's iterative version for deep merge because I don't like potential stack overflows of recursive.
local merge_task = {}
function merge_to_left_o(orig, new)
merge_task[orig] = new
local left = orig
while left ~= nil do
local right = merge_task[left]
for new_key, new_val in pairs(right) do
local old_val = left[new_key]
if old_val == nil then
left[new_key] = new_val
else
local old_type = type(old_val)
local new_type = type(new_val)
if (old_type == "table" and new_type == "table") then
merge_task[old_val] = new_val
else
left[new_key] = new_val
end
end
end
merge_task[left] = nil
left = next(merge_task)
end
end

I preferred James version for its simplicity and use it in my utils.lua - i did add a check for table type for error handling.
function merge(a, b)
if type(a) == 'table' and type(b) == 'table' then
for k,v in pairs(b) do if type(v)=='table' and type(a[k] or false)=='table' then merge(a[k],v) else a[k]=v end end
end
return a
end
Thanks for this nice function which should be part of the table class so you could call a:merge(b) but doing table.merge = function(a, b) ... did not work for me. Could even be compressed to a one liner for the real nerds :)

Like Doug Currie said, you can use his function, but there is a problem with his method. If first_table has things in it's k index, the function will over write it.
I'm assuming you're trying to merge these tables, not overwrite index's and value's. So this would be my method, it's very similar but is used for merging tables.
for _, v in pairs(second_table) do table.insert(first_table, v) end
The only problem with this solution is that the index is set as numbers, not as strings. This will work with tables with numbers as the index, and for tables with strings as their index, use Doug Currie's method.
Doug Currie's method:
for k,v in pairs(second_table) do first_table[k] = v end

Extending this great answer, https://stackoverflow.com/a/1283399/1570165, I would like to go with a (pure) functional approach like this one below:
-- example values
local t1 = { a = 0, b = 2 }
local t2 = { a = 1, c = 3 }
-- merge function that takes functional approach
local merge = function(a, b)
local c = {}
for k,v in pairs(a) do c[k] = v end
for k,v in pairs(b) do c[k] = v end
return c
end
-- t1 and t2 value still same after merge
print(merge(t1, t2)) -- { a = 1, b = 2, c = 3 }
print(t2) -- { a = 1, c = 3 }
print(t1) -- { a = 0, b = 2 }

for k,v in pairs(t2) do t1[k] = v end
key for string solution

Related

MATLAB dynamically read/write attributes - getattr, setattr?

class A(): pass
a = A()
setattr(a, 'dog', True)
Is there a MATLAB equivalent? If not, what's the most compact alternative? Currently I do
for i=1:length(keys)
k = keys{i};
v = values{i};
if k == "arg1"
obj.arg1 = v;
elseif k == "arg2"
obj.arg2 = v;
...
Likewise for getattr? If needed, assume all keys are already Properties.
Non-Python readers: setattr(obj, 'a', 1) <=> obj.a = 1 and getattr(obj, 'a') <=> obj.a.
obj.arg1 is the same as obj.('arg1').
So in your code snippet is equivalent to:
for i=1:length(keys)
obj.(keys{i}) = values{i};
end

remove duplicates in a table (rexx language)

I have a question about removing duplicates in a table (rexx language), I am on netphantom applications that are using the rexx language.
I need a sample on how to remove the duplicates in a table.
I do have a thoughts on how to do it though, like using two loops for these two tables which are A and B, but I am not familiar with this.
My situation is:
rc = PanlistInsertData('A',0,SAMPLE)
TABLE A (this table having duplicate data)
123
1
1234
12
123
1234
I need to filter out those duplicates data into TABLE B like this:
123
1234
1
12
You can use lookup stem variables to test if you have already found a value.
This should work (note I have not tested so there could be syntax errors)
no=0;
yes=1
lookup. = no /* initialize the stem to no, not strictly needed */
j=0
do i = 1 to in.0
v = in.i
if lookup.v <> yes then do
j = j + 1
out.j = v
lookup.v = yes
end
end
out.0 = j
You can eliminate the duplicates by :
If InStem first element, Move the element to OutStem Else check all the OutStem elements for the current InStem element
If element is found, Iterate to the next InStem element Else add InStem element to OutStem
Code Snippet :
/*Input Stem - InStem.
Output Stem - OutStem.
Array Counters - I, J, K */
J = 1
DO I = 1 TO InStem.0
IF I = 1 THEN
OutStem.I = InStem.I
ELSE
DO K = 1 TO J
IF (InStem.I ?= OutStem.K) & (K = J) THEN
DO
J = J + 1
OutStem.J = InStem.I
END
ELSE
DO
IF (InStem.I == OutStem.K) THEN
ITERATE I
END
END
END
OutStem.0 = J
Hope this helps.

Matlab name assignment

I am trying to decrease some big chucks of matlab code i had from a while ago, and was hoping to get them a bit more "clean".
The VarName2,VarName3,VarName4 ...etc are provide by measured data and i will know what they are always going to be thus i gave me the name A,B ,C , the think i want changed though is the first part of the name, so every time i run the .m file I will use the input('') option
where as fname = 'SWAN' and A, B , C are the second part of the name and they are constant.
fname = input ('enter name')
fname_A = VarName2
fname_B = VarName3
fname_C = VarName4
and want to be getting
SWAN_A = VarName2
SWAN_B = VarName3
SWAN_C = VarName4
thank you
Following your advices I been trying the structure construction
S.name = input ('enter name of the data ".." ==')
S.A = A;
S.A(1,:)=[];
S.B = B;
S.B(1,:)=[];
S.C = C;
S.C(1,:)=[];
S.D = D;
S.D(1,:)=[];
S.E = E;
S.E(1,:)=[];
may i ask if i can also have an input thing command so i can change the name of the structure?
Precede the script with S='west' and then do
'S'.name = input ('enter name of the data ".." ==')
S.A = A;
Here is how I would probably store the information that you are handling:
S.name = input ('enter name')
S.A = VarName2
S.B = VarName3
S.C = VarName4
And if you want to do it a few times:
for t=3:-1:1
S(t).name = input ('enter name')
S(t).A = VarName2
S(t).B = VarName3
S(t).C = VarName4
end
In this way you could now find the struct named 'swan':
idx = strcmpi({S.name},'SWAN')
you can use eval
eval( sprintf('%s_A = VarName2;', fname ) );
eval( sprintf('%s_B = VarName3;', fname ) );
eval( sprintf('%s_C = VarName4;', fname ) );
Note that the use of eval is not recommended.
One alternative option may be to use struct with dynamic field names:
A.( fname ) = VarName2;
B.( fname ) = VarName3;
C.( fname ) = VarName4;
Now you have three structs (A, B and C) with A.SWAN equal to VarName2, B.SWAN equal to VarName3 etc.

nested for loop query

I am trying to do something rather simple, but can't seem to get it...
I have 3 cell-arrays with strings,
A = {'ConditionA'; 'ConditionB'; 'ConditionC'; 'ConditionD'};
B = {'Case1'; 'Case2'; 'Case3'; 'Case4'};
C = {'Rice'; 'Beans'; 'Carrots'; 'Cereal';'Tomato'; 'Cabbage';...
'Sugar'}
I want to produce a vector with the concatenated (strcat?) combinations, as it this were a "tree diagram", like:
strcat(A(1),B(1),C(1))
strcat(A(1),B(1),C(2))
strcat(A(1),B(1),C(3))
strcat(A(1),B(1),C(4))
strcat(A(1),B(1),C(5))
strcat(A(1),B(1),C(6))
strcat(A(1),B(1),C(7))
strcat(A(1),B(2),C(1))
So what the first elements I am trying to get are (in a column ideally):
ConditionACase1Rice
ConditionACase1Beans
ConditionACase1Carrots
ConditionACase1Cereal
ConditionACase1Tomato
ConditionACase1Cabbage
ConditionACase1Sugar
ConditionACase2Rice
etc etc etc...
I know that:
for i=1:length(A)
E(i) = strcat(A(i),B(1),C(1))
end
Works for one "level". I have tried:
for i=1:length(A)
for j=1:length(B)
for k=1:length(C)
P(i) = strcat(A(i),B(j),C(k));
end
end
end
But this doesn't work...
I would be really grateful if I could be helped with this.
Thanks in advance!
From what I understood, you want all possible combinations of the strings of the input arrays as specified. If so, simply replace your nested loops with the following:
P = cell(length(A)*length(B)*length(C),1);
t=1;
for i=1:length(A)
for j=1:length(B)
for k=1:length(C)
P(t) = strcat(A(i),B(j),C(k));
t = t+1;
end
end
end
For the input arrays,
>> A = {'ConditionA'; 'ConditionB'; 'ConditionC'; 'ConditionD'};
>> B = {'Case1'; 'Case2'; 'Case3'; 'Case4'};
>> C = {'Rice'; 'Beans'; 'Carrots'; 'Cereal';'Tomato'; 'Cabbage';'Sugar'};
The value of P would be:
>> P
P =
'ConditionACase1Rice'
'ConditionACase1Beans'
'ConditionACase1Carrots'
'ConditionACase1Cereal'
'ConditionACase1Tomato'
'ConditionACase1Cabbage'
'ConditionACase1Sugar'
'ConditionACase2Rice'
'ConditionACase2Beans'
'ConditionACase2Carrots'
'ConditionACase2Cereal'
'ConditionACase2Tomato'
'ConditionACase2Cabbage'
'ConditionACase2Sugar'
'ConditionACase3Rice'
'ConditionACase3Beans'
'ConditionACase3Carrots'
'ConditionACase3Cereal'
'ConditionACase3Tomato'
'ConditionACase3Cabbage'
'ConditionACase3Sugar'
'ConditionACase4Rice'
'ConditionACase4Beans'
'ConditionACase4Carrots'
'ConditionACase4Cereal'
'ConditionACase4Tomato'
'ConditionACase4Cabbage'
'ConditionACase4Sugar'
'ConditionBCase1Rice'
'ConditionBCase1Beans'
'ConditionBCase1Carrots'
'ConditionBCase1Cereal'
'ConditionBCase1Tomato'
'ConditionBCase1Cabbage'
'ConditionBCase1Sugar'
'ConditionBCase2Rice'
'ConditionBCase2Beans'
'ConditionBCase2Carrots'
'ConditionBCase2Cereal'
'ConditionBCase2Tomato'
'ConditionBCase2Cabbage'
'ConditionBCase2Sugar'
'ConditionBCase3Rice'
'ConditionBCase3Beans'
'ConditionBCase3Carrots'
'ConditionBCase3Cereal'
'ConditionBCase3Tomato'
'ConditionBCase3Cabbage'
'ConditionBCase3Sugar'
'ConditionBCase4Rice'
'ConditionBCase4Beans'
'ConditionBCase4Carrots'
'ConditionBCase4Cereal'
'ConditionBCase4Tomato'
'ConditionBCase4Cabbage'
'ConditionBCase4Sugar'
'ConditionCCase1Rice'
'ConditionCCase1Beans'
'ConditionCCase1Carrots'
'ConditionCCase1Cereal'
'ConditionCCase1Tomato'
'ConditionCCase1Cabbage'
'ConditionCCase1Sugar'
'ConditionCCase2Rice'
'ConditionCCase2Beans'
'ConditionCCase2Carrots'
'ConditionCCase2Cereal'
'ConditionCCase2Tomato'
'ConditionCCase2Cabbage'
'ConditionCCase2Sugar'
'ConditionCCase3Rice'
'ConditionCCase3Beans'
'ConditionCCase3Carrots'
'ConditionCCase3Cereal'
'ConditionCCase3Tomato'
'ConditionCCase3Cabbage'
'ConditionCCase3Sugar'
'ConditionCCase4Rice'
'ConditionCCase4Beans'
'ConditionCCase4Carrots'
'ConditionCCase4Cereal'
'ConditionCCase4Tomato'
'ConditionCCase4Cabbage'
'ConditionCCase4Sugar'
'ConditionDCase1Rice'
'ConditionDCase1Beans'
'ConditionDCase1Carrots'
'ConditionDCase1Cereal'
'ConditionDCase1Tomato'
'ConditionDCase1Cabbage'
'ConditionDCase1Sugar'
'ConditionDCase2Rice'
'ConditionDCase2Beans'
'ConditionDCase2Carrots'
'ConditionDCase2Cereal'
'ConditionDCase2Tomato'
'ConditionDCase2Cabbage'
'ConditionDCase2Sugar'
'ConditionDCase3Rice'
'ConditionDCase3Beans'
'ConditionDCase3Carrots'
'ConditionDCase3Cereal'
'ConditionDCase3Tomato'
'ConditionDCase3Cabbage'
'ConditionDCase3Sugar'
'ConditionDCase4Rice'
'ConditionDCase4Beans'
'ConditionDCase4Carrots'
'ConditionDCase4Cereal'
'ConditionDCase4Tomato'
'ConditionDCase4Cabbage'
'ConditionDCase4Sugar'
Let me know if you need further assistance.
I am not really familiar with matlab.. but maybe try something like this?
for A = {'ConditionA'; 'ConditionB'; 'ConditionC'; 'ConditionD'};
for B = {'Case1'; 'Case2'; 'Case3'; 'Case4'};
for C = {'Rice'; 'Beans'; 'Carrots'; 'Cereal';'Tomato'; 'Cabbage'; 'Sugar'}
P(i) = strcat(A(i),B(j),C(k));
end
end
end
{
x = 1;
for i=1:length(A)
for j=1:length(B)
for k=1:length(C)
P(x) = strcat(A(i),B(j),C(k));
x = x + 1;
end
end
end
}
Please basically check your code before posting to PO as this is a very simple debugging

Recursive concatenation of Matlab structs

Is it somehow possible to concatenate two matlab structures recursively without iterating over all leaves of one of the structures.
For instance
x.a=1;
x.b.c=2;
y.b.d=3;
y.a = 4 ;
would result in the following
res = mergeStructs(x,y)
res.a=4
res.b.c=2
res.b.d=3
The following function works for your particular example. There will be things it doesn't consider, so let me know if there are other cases you want it to work for and I can update.
function res = mergeStructs(x,y)
if isstruct(x) && isstruct(y)
res = x;
names = fieldnames(y);
for fnum = 1:numel(names)
if isfield(x,names{fnum})
res.(names{fnum}) = mergeStructs(x.(names{fnum}),y.(names{fnum}));
else
res.(names{fnum}) = y.(names{fnum});
end
end
else
res = y;
end
Then res = mergeStructs(x,y); gives:
>> res.a
ans =
4
>> res.b
ans =
c: 2
d: 3
as you require.
EDIT: I added isstruct(x) && to the first line. The old version worked fine because isfield(x,n) returns 0 if ~isstruct(x), but the new version is slightly faster if y is a big struct and ~isstruct(x).