3
$\begingroup$

I'm working with a nested list (labeled here as allEntries) and I'm trying to insert some additional columns. My list has 12 categories, each category has a different number of entries, and each entry starts with 15 elements.

I'm trying to add 3 more elements, and currently I'm doing it one element at a time using table and insert. For instance the first thing I want to add is the day of the week explicitly

allEntries  = 
Table[
    Insert[
        allEntries[[j, i]],
        DateString[{allEntries[[j, i, 2]], {"Month", "Day", "Year", "Hour", "Minute"}}, "DayName"],
         3],
{j, 1, Length[shapes]},
{i, 1, Length[allEntries[[j]]]}
];

Here j goes from 1 to 12, and then i goes from 1 to the number of entries in the category (anywhere from a few hundred to a few 10s of thousands). I'm simply converting the date into a simple day of the week to make it easier to select later on, and I want this added at position 3.

This works fine, but I'm doing it two more times to add other data in the same fashion, and it seems like there should be a way to add this in one step.

$\endgroup$
3
$\begingroup$

Multiple inserts can be made using Fold or ReplaceAll, e.g.

list = {1, 2, 3, 4, 5, 6, 7, 8, 9};

Fold[Insert[#1, First[#2], Last[#2]] &, list, {{"a", 2}, {"b", 4}, {"c", 6}}]

{1, a, 2, b, 3, c, 4, 5, 6, 7, 8, 9}

list /. {x_Integer, y_, z_, rest__} :> {x, "a", y, "b", z, "c", rest}

{1, a, 2, b, 3, c, 4, 5, 6, 7, 8, 9}

Applied to the OP's data structure.

shapes = Range[12];
r = ReplacePart[Range[15], 2 -> "Nov 9 2017 13:24"];

save = allEntries = {
    {r, r, r},
    {r, r},
    {r, r, r, r},
    {r},
    {r, r, r, r},
    {r, r, r},
    {r},
    {r, r, r, r},
    {r, r},
    {r, r, r},
    {r},
    {r, r, r, r}
    };

Demonstrating the OP's single insert function.

allEntries = Table[Insert[allEntries[[j, i]],
    DateString[{allEntries[[j, i, 2]],
      {"Month", "Day", "Year", "Hour", "Minute"}}, "DayName"], 3],
   {j, 1, Length[shapes]}, {i, 1, Length[allEntries[[j]]]}];

allEntries[[1, 1]]

{1, Nov 9 2017 13:24, Thursday, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

Resetting allEntries for the Fold method.

allEntries = save;

allEntries = Table[
   Fold[Insert[#1, First[#2], Last[#2]] &, 
    allEntries[[j, i]], {{DateString[{allEntries[[j, i, 2]],
        {"Month", "Day", "Year", "Hour", "Minute"}}, "DayName"], 3},
     {DateString[DatePlus[
        allEntries[[j, i, 2]], {1, "Day"}], "DayName"], 4},
     {DateString[DatePlus[
        allEntries[[j, i, 2]], {2, "Day"}], "DayName"], 5}}],
   {j, 1, Length[shapes]}, {i, 1, Length[allEntries[[j]]]}];

allEntries[[1, 1]]

{1, Nov 9 2017 13:24, Thursday, Friday, Saturday, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

Easier usingReplaceAll.

allEntries = save;

allEntries = allEntries /. {a_Integer, date_, rest__} :> {a, date,
    DateString[{date,
      {"Month", "Day", "Year", "Hour", "Minute"}}, "DayName"],
    DateString[DatePlus[date, {1, "Day"}], "DayName"],
    DateString[DatePlus[date, {2, "Day"}], "DayName"], rest}

allEntries[[1, 1]]

{1, Nov 9 2017 13:24, Thursday, Friday, Saturday, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}

$\endgroup$
  • $\begingroup$ I'm somewhat surprised that the Fold method doesn't speed up my process much. Using my method, with three separate inserts, took 174.297s. Switching it to use Fold took 168.75 seconds. It seems like with my initial method, I'm looping over the whole list three times, but with Fold I only loop through it once, is that correct? I haven't tried the ReplaceAll method, I'm still trying to understand how it works. $\endgroup$ – winstondc Nov 9 '17 at 16:36
  • $\begingroup$ Fold is essentially looping over the parameter list, so three inserts is three loops. I expect ReplaceAll will be significantly quicker. $\endgroup$ – Chris Degnen Nov 9 '17 at 17:12
  • $\begingroup$ I'm having a hard time understanding how your replace all command works. I get that a_Integer picks out integers and just leaves them alone, but I don't understand how you only have three entities on the LHS (a_Integer, date_, rest__), with what to me would seem like 5 rules on the RHS. I'm also not clear on what rest__ is doing, but I see that if I remove it, it doesn't work. Can you elaborate on that code somewhat? $\endgroup$ – winstondc Nov 10 '17 at 12:48
  • $\begingroup$ The replacement is of the form {a_, b_, c_}:>{a, 1, b, c} converting a three element list to a four element list with 1 added in the second place. rest__ has two underscores meaning one or more element, so the example could be {a_, rest__}:>{a, 1, rest} producing the same result. a_Integer is used to make sure only 'entry' patterns are matched, not category ones. SetDelayed :> localised a, b, c & rest, so if any other a has a value it doesn't affect the replacement. See also final examples here. $\endgroup$ – Chris Degnen Nov 10 '17 at 13:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.