# Rewrite the list without certain elements in the sequence

I have a list1:

list1={{" r1 =", 0., " r2 =", 0., " t =", 0.043, " RK =", 0.94}, {" r1 =",
0., " r2 =", 0., " t =", 0.130, " RK =", 2.5}, {" r1 =", 0.,
" r2 =", 0., " t =", 0.218, " RK =", 5.29}, {" r1 =", 5., " r2 =",
5., " t =", 6.152, " RK =", 1.498}, {" r1 =", 5., " r2 =", 5.,
" t =", 6.239, " RK =", 4.094}}


I need to get list2 from list1.

list2={{{0., 0., 0.043},
0.94}, {{0., 0., 0.130}, 2.5}, {{0., 0., 0.218},
5.29}, {{5., 5., 6.152}, 1.498}, {{5., 5., 6.239}, 4.094}}


To get list2, I have removed strings and added extra curly braces around every first three elements. Is it possible to do this without a lot of loops? Could you show it?

In my original lists, there are a few thousand elements.

Here's a way:

FlattenAt[TakeDrop[#, 3], -1] & /@ DeleteCases[list1, _String, Infinity]


Explanation:

We start by deleting the strings

DeleteCases[list1, _String, Infinity]


Adding the extra layer of list structure to the first three element is a bit trickier, and maybe someone else will have something more elegant to suggest. TakeDrop gets you close. For example:

TakeDrop[{0., 0., 0.043, 0.94}, 3]
(* {{0., 0., 0.043}, {0.94}} *)


We don't like that extra list at the last position. One way to get rid of it is to FlattenAt:

FlattenAt[TakeDrop[{0., 0., 0.043, 0.94}, 3], -1]
(* {{0., 0., 0.043}, 0.94} *)


Okay, now turn that into a function that we can map over our "clean" data, and you have what I posted first above.

res1 = {Most@#, Last@#} & /@ DeleteCases[list1, _?(StringQ), {2}]


OR

res2 = SequenceReplace[
list1, {{a_String, b_?NumericQ, c_String, d_?NumericQ, e_String,
f_?NumericQ, g_String, h_?NumericQ}} :> {{b, d, f}, h}
]


OR

res3 = {#[[1 ;; 3]], #[[-1]]} &@#[[2 ;; -1 ;; 2]] & /@ list1


OR

res4 = First@SequenceReplace[#, {a_, b_, c_, d_} :> {{a, b, c}, d}] & /@
(SequenceReplace[#, {a_String, b_?NumericQ} :> b] & /@ list1)


Output:

> {{{0., 0., 0.043}, 0.94}, {{0., 0., 0.13}, 2.5}, {{0., 0., 0.218},
>   5.29}, {{5., 5., 6.152}, 1.498}, {{5., 5., 6.239}, 4.094}}


Check:

res1 == res2 == res3 == res4 == list2


True

Using GatherBy:

{Most@#, Last@#} & @@@ Outer[List, Last@GatherBy[#, Head] & /@ list1, 1] === list2

(*True*)

res = list1 /. {_, r1_, _, r2_, _, t_, _, rk_} :> {{r1, r2, t}, rk}
res == list2
(* True *)

result = list1 /. _String :> Nothing /. {a__, b_Real} :> {{a}, b};

result == list2


True