summing & matching cell arrays of different sizes - arrays

I have a 4016 x 4 cell, called 'totalSalesCell'. The first two columns contain text the remaining two are numeric.
1st field CompanyName
2nd field UniqueID
3rd field NumberItems
4th field TotalValue
In my code I have a loop which goes over the last month in weekly steps - i.e. 4 loops.
At each loop my code returns a cell of the same structure as totalSalesCell, called weeklySalesCell which generally contains a different number of rows to totalSalesCell.
There are two things I need to do. First if weeklySalesCell contains a company that is not in totalSalesCell it needs to be added to totalSalesCell, which I believe the code below will do for me.
co_list = unique([totalSalesCell(:, 1); weeklySalesCell (:, 1)]);
index = ismember(co_list, totalSalesCell(:, 1));
new_co = co_list(index==0, :);
totalSalesCell = [totalSalesCell; new_co];
The second thing I need to do and am unsure of the best way of going about it is to then add the weeklySalesCell numeric fields to the totalSalesCell. As mentioned the cells will 90% of the time have different row numbers so cannot apply a simple addition. Below is an example of what I wish to achieve.
totalSalesCell weeklySalesCell Result
co_id sales_value co_id sales_value co_id sales_value
23DFG 5 DGH84 3 23DFG 5
DGH84 6 ABC33 1 DGH84 9
12345 7 PLM78 4 ABC33 1
PLM78 4 12345 3 12345 10
KLH11 11 PLM78 8
KLH11 11

I believe the following codes must take care of both of your tasks -
[x1,x2] = ismember(totalSalesCell(:,1),weeklySalesCell(:,1))
corr_c2 = nonzeros(x1.*x2)
newval = cell2mat(totalSalesCell(x1,2)) + cell2mat(weeklySalesCell(corr_c2,2))
totalSalesCell(x1,2) = num2cell(newval)
excl_c2 = ~ismember(weeklySalesCell(:,1),totalSalesCell(:,1))
out = vertcat(totalSalesCell,weeklySalesCell(excl_c2,:)) %// desired output
Output -
out =
'23DFG' [ 5]
'DGH8444' [ 9]
'12345' [10]
'PLM78' [ 8]
'KLH11' [11]
'ABC33' [ 1]

Related

Renaming arrays of varying sizes

In Step 1, I find what type of data exists in Database.
In step 2, I retrieve all data from Database and try to store into arrays of varying sizes
1. Accessing data from MongoDB
mong <- mongo(collection = "mycollection", db = "dbname", url = "mongodb://localhost")
agg_df <- mong$aggregate('[{ "$group" :
{ "_id" : "$tagname",
"number_records" : { "$sum" : 1}
}
}]')
print(agg_df)
OUTPUT:
_id number_records
1 raees 100
2 DearZindagi 100
3 FAN 100
4 DDD 21
NOTE: Step 1 output indicates that there are 4 types of categories with records of 100,100,100,21 each.
2. From STEP 1, I need to create 4 arrays consisting of 1 column and varying nos. of rows(100,100,100,21) and give names to those array as Raees,DearZindagi,FAN,DDD
Dataset <- mong$find('{}','{"text":1}')
Dataset$text <- sapply(Dataset$text,function(row) iconv(row, "latin1", "ASCII", sub=""))
typeof(Dataset$text)
> [1] "character"
3. The arrays and their sizes(in rows) to be created is dependent on output of Step 1. There would never be a case where the output of step 1 would be more than 15 rows.
How should i do this?.
The split function would splits the Dataset into arrays, how shall i rename these arrays:
rows <- nrow(agg_df)
for (i in 1:rows){
array<- split(Dataset$text, rep(1:rows, c(agg_df[i,2])))
}

Using anonymous function rather than looping for summing up values in cell array

I have a matrix called data. It contains 3 columns, company name, company value & company currency, bit like below.
Name Value Currency
ABC 10 USD
MNO 5 JPY
PLM 3 USD
NJK 7 EUR
I need to sum the total value for each currency so my answer would look like below,
Currency Value
EUR 7
JPY 5
USD 13
I know I can do this using a loop but is it possible using an anonymous function and if so how?
Update - Extra information as original post lacked information
Below is my solution, which works. However I have seen people use cellFun or anonymous functions and fell like there is a more efficient way (and would to like alternative way) for problems of this nature
val = cell2mat(data(:, 2)); % double - value
sedols = data(:, [1 3]); % cell - name (1st column) and currency (2nd column)
ccy = unique(sedols(:, 2));
fx_exp = zeros(length(ccy(:, 1)), 1);
for n = 1 : length(ccy(:, 1))
index = strmatch(ccy(n, 1), sedols(:, 2));
fx_exp(n, 1) = sum(val(index));
end
Using cellfun or arrayfun is not more efficient than a simple loop. To take advantage of vectorization you need to work with pure double arrays.
Assuming your data is stored in a cell array, unique combined with accumarray is the way to go:
data = {
'ABC' 10 'USD'
'MNO' 5 'JPY'
'PLM' 3 'USD'
'NJK' 7 'EUR' };
[a,b,subs] = unique(data(:,3))
vals = [data{:,2}];
currsum = accumarray(subs,vals)
out = [data(b,3) num2cell(currsum)]
out =
'EUR' [ 7]
'JPY' [ 5]
'USD' [13]

Check 2d array for same values

I am trying to make a game and i have a 2d array
So its like this:
Grid[x][y]
lets pretend these values are in it:
Column 1 Column 2 Column 3 Column 4 Column 5
1 2 5 2 5
2 2 3 1 1
1 4 3 4 5
1 3 3 3 5 <-- match this row
3 5 3 4 5
2 4 3 4 5
2 4 4 4 5
In the middle (index 4) i want to check if there are at least 3 times the same number and what about if there are 4 times the same or even 5.
How do you check this ? What would be a good way to find the same and delete those that are the same... I am stuck to figure out the logic to make something like this
this is what i tried:
grid = {}
for x = 1, 5 do
grid[x] = {finish = false}
for y = 1, 7 do
grid[x][y] = {key= math.random(1,4)}
end
end
function check(t)
local tmpArray = {}
local object
for i = 1,5 do
object = t[i][1].key
if object == t[i+1][1].key then
table.insert( tmpArray, object )
else
break
end
end
end
print_r(grid)
check(grid)
print_r(grid)
where print_r prints the grid:
function print_r ( t )
local print_r_cache={}
local function sub_print_r(t,indent)
if (print_r_cache[tostring(t)]) then
print(indent.."*"..tostring(t))
else
print_r_cache[tostring(t)]=true
if (type(t)=="table") then
for pos,val in pairs(t) do
if (type(val)=="table") then
print(indent.."["..pos.."] => "..tostring(t).." {")
sub_print_r(val,indent..string.rep(" ",string.len(pos)+8))
print(indent..string.rep(" ",string.len(pos)+6).."}")
else
print(indent.."["..pos.."] => "..tostring(val))
end
end
else
print(indent..tostring(t))
end
end
end
sub_print_r(t," ")
end
It doesnt work that great because i check with the index after that one and if that isnt the same it doesnt add the last one..
I dont know if it is the best way to go...
If i "delete" the matched indexes my plan is to move the index row above or beneath it into the 4 index row... but first things first
You should compare the second index not the first: in the table
g = {{1,2,3}, {4,5,6}}
g[1] is first row i.e. {1,2,3}, not {1,4} the first column (first element of first and second rows). You were doing same thing in previous post of yours, you should reread the Lua docs about tables. You should do something like
for i = 1,#t do
object = t[i][1].key
if object == t[i][2].key then
This will only compare first two items in row. If you want to check whether the row has any identical consecutive items you will have to loop over the second index from 1 to #t[i]-1.
You might find the following print function much more useful, as it prints table as a grid, easier to see before/after:
function printGrid(g)
for i, t in ipairs(g) do
print('{' .. table.concat(t, ',') .. '}')
end
end

How do I make this specific code run faster in Matlab?

I have an array with a set of chronological serial numbers and another source array with random serial numbers associated with a numeric value. The code creates a new cell array in MATLAB with the perfectly chronological serial numbers in one column and in the next column it inserts the associated numeric value if the serial numbers match in both original source arrays. If they don't the code simply copies the previous associated value until there is a new match.
j = 1;
A = {random{1:end,1}};
B = cell2mat(A);
value = random{1,2};
data = cell(length(serial), 1);
data(:,1) = serial(:,1);
h = waitbar(0,'Please Wait...');
steps = length(serial);
for k = 1:length(serial)
[row1, col1, vec1] = find(B == serial{k,1});
tf1 = isempty(vec1);
if (tf1 == 0)
prices = random{col1,2};
data(j,2) = num2cell(value);
j = j + 1;
else
data(j,2) = num2cell(value);
j = j + 1;
end
waitbar(k/steps,h,['Please Wait... ' num2str(k/steps*100) ' %'])
end
close(h);
Right now, the run-time for the code is approximately 4 hours. I would like to make this code run faster. Please suggest any methods to do so.
UPDATE
source input (serial)
1
2
3
4
5
6
7
source input (random)
1 100
2 105
4 106
7 107
desired output (data)
SR No Value
1 100
2 105
3 105
4 106
5 106
6 106
7 107
Firstly, run the MATLAB profiler (see 'doc profile') and see where the bulk of the execution time is occuring.
Secondly, don't update the waitbar on every iteration> Particularly if serial contains a large (> 100) number of elements.
Do something like:
if (mod(k, 100)==0) % update on every 100th iteration
waitbar(k/steps,h,['Please Wait... ' num2str(k/steps*100) ' %'])
end
Some points:
Firstly it would help a lot if you gave us some sample input and output data.
Why do you initialize data as one column and then fill it's second in the loop? Rather initialize it as 2 columns upfront: data = cell(length(serial), 2);
Is j ever different from k, they look identical to me and you could just drop both the j = j + 1 lines.
tf1 = isempty(vec1); if (tf1 == 0)... is the same as the single line: if (!isempty(vec1)) or even better if(isempty(vec1)) and then swap the code from your else and your if.
But I think you can probably find a fast vecotrized solution if you provide some (short) sample input and output data.

Changing indices and order in arrays

I have a struct mpc with the following structure:
num type col3 col4 ...
mpc.bus = 1 2 ... ...
2 2 ... ...
3 1 ... ...
4 3 ... ...
5 1 ... ...
10 2 ... ...
99 1 ... ...
to from col3 col4 ...
mpc.branch = 1 2 ... ...
1 3 ... ...
2 4 ... ...
10 5 ... ...
10 99 ... ...
What I need to do is:
1: Re-order the rows of mpc.bus, such that all rows of type 1 are first, followed by 2 and at last, 3. There is only one element of type 3, and no other types (4 / 5 etc.).
2: Make the numbering (column 1 of mpc.bus, consecutive, starting at 1.
3: Change the numbers in the to-from columns of mpc.branch, to correspond to the new numbering in mpc.bus.
4: After running simulations, reverse the steps above to turn up with the same order and numbering as above.
It is easy to update mpc.bus using find.
type_1 = find(mpc.bus(:,2) == 1);
type_2 = find(mpc.bus(:,2) == 2);
type_3 = find(mpc.bus(:,2) == 3);
mpc.bus(:,:) = mpc.bus([type1; type2; type3],:);
mpc.bus(:,1) = 1:nb % Where nb is the number of rows of mpc.bus
The numbers in the to/from columns in mpc.branch corresponds to the numbers in column 1 in mpc.bus.
It's OK to update the numbers on the to, from columns of mpc.branch as well.
However, I'm not able to find a non-messy way of retracing my steps. Can I update the numbering using some simple commands?
For the record: I have deliberately not included my code for re-numbering mpc.branch, since I'm sure someone has a smarter, simpler solution (that will make it easier to redo when the simulations are finished).
Edit: It might be easier to create normal arrays (to avoid woriking with structs):
bus = mpc.bus;
branch = mpc.branch;
Edit #2: The order of things:
Re-order and re-number.
Columns (3:end) of bus and branch are changed. (Not part of this question)
Restore original order and indices.
Thanks!
I'm proposing this solution. It generates a n x 2 matrix, where n corresponds to the number of rows in mpc.bus and a temporary copy of mpc.branch:
function [mpc_1, mpc_2, mpc_3] = minimal_example
mpc.bus = [ 1 2;...
2 2;...
3 1;...
4 3;...
5 1;...
10 2;...
99 1];
mpc.branch = [ 1 2;...
1 3;...
2 4;...
10 5;...
10 99];
mpc.bus = sortrows(mpc.bus,2);
mpc_1 = mpc;
mpc_tmp = mpc.branch;
for I=1:size(mpc.bus,1)
PAIRS(I,1) = I;
PAIRS(I,2) = mpc.bus(I,1);
mpc.branch(mpc_tmp(:,1:2)==mpc.bus(I,1)) = I;
mpc.bus(I,1) = I;
end
mpc_2 = mpc;
% (a) the following mpc_tmp is only needed if you want to truly reverse the operation
mpc_tmp = mpc.branch;
%
% do some stuff
%
for I=1:size(mpc.bus,1)
% (b) you can decide not to use the following line, then comment the line below (a)
mpc.branch(mpc_tmp(:,1:2)==mpc.bus(I,1)) = PAIRS(I,2);
mpc.bus(I,1) = PAIRS(I,2);
end
% uncomment the following line, if you commented (a) and (b) above:
% mpc.branch = mpc_tmp;
mpc.bus = sortrows(mpc.bus,1);
mpc_3 = mpc;
The minimal example above can be executed as is. The three outputs (mpc_1, mpc_2 & mpc_3) are just in place to demonstrate the workings of the code but are otherwise not necessary.
1.) mpc.bus is ordered using sortrows, simplifying the approach and not using find three times. It targets the second column of mpc.bus and sorts the remaining matrix accordingly.
2.) The original contents of mpc.branch are stored.
3.) A loop is used to replace the entries in the first column of mpc.bus with ascending numbers while at the same time replacing them correspondingly in mpc.branch. Here, the reference to mpc_tmp is necessary so ensure a correct replacement of the elements.
4.) Afterwards, mpc.branch can be reverted analogously to (3.) - here, one might argue, that if the original mpc.branch was stored earlier on, one could just copy the matrix. Also, the original values of mpc.bus are re-assigned.
5.) Now, sortrows is applied to mpc.bus again, this time with the first column as reference to restore the original format.

Resources