You'll find for other uses of your financial data that things run faster if you initially convert to absolute times.
list1[[All, 1]] = AbsoluteTime /@ list1[[All, 1]];
list2[[All, 1]] = AbsoluteTime /@ list2[[All, 1]];
This is the sort of problem that you'll probably find lots of different approaches posted. I'd take the complement and give it a null value -- though you can choose something else -- and make a new list. My stepwise approach is:
addToList = Complement[list2[[All, 1]], list1[[All, 1]]];
addToList = {#, Null} & /@ addToList;
list1 = Sort@Join[list1, addToList1]
then replace the nulls with the value immediately before it:
positions = Position[list1, {_,Null}];
(list1[[#, 2]] = list1[[# - 1, 2]]) & /@ positions
You would probably want to add a test to ensure that 1
does not exists in the list of positions (because if position #1 is one of your dates you have no previous value to replace the value with).
You could also use a rule replacement approach here but I am conscious of your financial data probably being a few hundred, or much more, elements and the different dates only being a handful. Therefore I am choosing Part
because it should be more efficient.
Alternatively it is not really necessary to programmatically find the dates that are missing because these are known to you as a trader on financial markets from the published dates on which the various world exchanges operate. In other words addToList
above can readily be constructed manually and saved permanently as a constant.
In any case, as a function:
newList[l1_, l2_] :=
Module[{addToList, positions, list1 = l1, list2 = l2},
addToList = {#, Null} & /@ Complement[list2[[All, 1]], list1[[All, 1]]];
list1 = Sort@Join[list1, addToList];
positions = DeleteCases[Position[list1, {_, Null}],1];
(list1[[#, 2]] = list1[[# - 1, 2]]) & /@ positions;
list1
]
where the arguments to newList
are the test list first and then the comparator list.
newList[list1, list2]
(* {{{2007, 1, 2}, 12.04}, {{2007, 1, 3}, 12.04}, {{2007, 1, 4},
11.51}, {{2007, 1, 5}, 12.14}} *)
and to operate on list2
newList[list2, list1]
To test the efficiency of methods you could use FinancialData
to download say microsoft from the NY exchange and Barclays from the London exchange etc. I thought it would be more fun to make some dummy data.
SeedRandom[1];
days1 = Union@RandomInteger[{1, 365}, {400}];
SeedRandom[2];
days2 = Union@RandomInteger[{1, 365}, {400}];
in the next lines you could use DateList
instead of AbsoluteTime
but as above I think it is best to stick with absolute times.
list1 = {AbsoluteTime[#], RandomReal[{1, 30}]} & /@ Thread[{2012, 1, days1}]
list2 = {AbsoluteTime[#], RandomReal[{1, 30}]} & /@ Thread[{2012, 1, days2}]
Timing[
new1 = newList[list1, list2];
new2 = newList[list2, list1];
]
(* {0.006115, Null} *)
new1[[All, 1]] == new2[[All, 1]]
(* True *)
this was on a 2006 mac mini running 10.6.8 with Mma 8.0.4
Edit
The test data offered by the OP is flawed because it does not enable the specifications to be satisfied. So we can either use a test data set as above or trim the OPs test data. Timing again is on an old 2006 mac mini.
list1 = FinancialData["PETR4.SA", {"2007"}];
list2 = FinancialData["XOM", {"2007"}];
As above the first list has to have its first element removed for the OPs specifications to work with this data.
Timing[
new1 = newList[Rest@list1, list2];
new2 = newList[list2, Rest@list1];
]
(* {0.001859, Null}*)
new1[[All, 1]] == new2[[All, 1]]
(* True *)
Dimensions[new1]
(* {256, 2} *)
list1
in the update)? You must fill only days present in one list or the other? That can be done by pre-processing with methods described in mathematica.stackexchange.com/q/15425/121 -- if you need help let me know. $\endgroup$