Tell me more ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Given a list of strings:

data = {
 "2894;Hot Pink;53:09:44;1449714",
 "17456;Dark Cyan;19:06:42;6929227",
 "5147;Lime;54:11:55;5247632"
}

(Words are separated by ";", the number of words in strings are equal. Number of characters in strings are unequal. Number of characterss in words are unequal.)

How to extract the $m^{th}$ through $n^{th}$ words, so that e.g. $m=2, n=3$ should return:

{
"Hot Pink;53:09:44",
"Dark Cyan;19:06:42",
"Lime;54:11:55"
}  

UPDATE

Final solution was found for the task.
I like to share it here.

inlist = RandomChoice[
{"7270;Deep Pink;04:14:55;0027354",
 "2871;Dark Orchid;54:21:23;1182263",
 "4021;Silver;04:00:58;6940040",
 "3521;Dark Slate Gray;18:42:43;5828275"}, 
400000];  

delim = ";";
fromWord = 2;
numberOfWords = 2;  

from = 2 fromWord - 1;
to = 2 (fromWord + numberOfWords - 1) - 1;
outlist = List /@ StringJoin /@
      StringSplit[inlist, delim -> delim][[All, from ;; to]]; // Timing  

{0.92, Null}  

The honor goes to the very concerned in this task. Every detail of their conception was vital to the solution. Keep'n rocking.

share|improve this question

3 Answers

f[data_, from_, to_, sep_] := StringSplit[#, sep][[from ;; to]] & /@ data;
data = {"2894;Hot Pink;53:09:44;1449714", 
        "17456;Dark Cyan;19:06:42;6929227", 
        "5147;Lime;54:11:55;5247632"};

f[data, 2, 3, ";"]
(*
->{{"Hot Pink", "53:09:44"}, {"Dark Cyan", "19:06:42"}, {"Lime", "54:11:55"}}
*)
share|improve this answer
nice use of StringSplit. However, I assumed the m and n are not a range. But meant to be the word m and the word n only. i.e. not all the words in between also. i.e. f[data,1,3,";"] should return only words 1` and 3 but not word 2 as well. At least this is what I understood the question to mean. – Nasser Dec 20 '12 at 10:58
+1, I think your solution is very nice. If you just use Part like this, then it will do it as I think the question asked (i.e. not using range, but the elements): f[data_, m_, n_, sep_] :=Part[StringSplit[#, ";"] & /@ data, All, {m, n}] in the first line you have in your function. Now f[data,1,3,";"] for example, will return only first and third word and all ok – Nasser Dec 20 '12 at 11:11
@NasserM.Abbasi Of course I can't be sure, but my interpretation comes from the use of the word throughin the OP's sentence Give a list of strings containing chars m'th "Word" through n'th "Word" in elements – belisarius Dec 20 '12 at 11:41
2  
StringSplit is Listable. Try: f[data_, from_, to_, sep_] := StringSplit[data, sep][[All, from ;; to]] – Mr.Wizard Dec 20 '12 at 11:55
humm.. for some reason I did not see that through word there when I first read the problem....any way, not important. I think StringSplit is the right function to use here. StringCases is not as easy to use for this. – Nasser Dec 20 '12 at 12:06
show 5 more comments

Specific case for $m=2$ and $n=3$:

data = {"2894;Hot Pink;53:09:44;1449714",
        "17456;Dark Cyan;19:06:42;6929227",
        "5147;Lime;54:11:55;5247632"};

First@StringCases[#, 
   StartOfString ~~ __ ~~ ";" ~~ x__ ~~ ";" ~~ y__ ~~ ";" :> x <> ";" <> y] & /@ data
{"Hot Pink;53:09:44", "Dark Cyan;19:06:42", "Lime;54:11:55"}

More general version for any $m, n$:

{m, n} = {2, 3}

StringDrop[StringJoin@Drop[
    StringCases[#, Shortest[__ ~~ ";"], n], m - 1], -1] & /@ data
{"Hot Pink;53:09:44", "Dark Cyan;19:06:42", "Lime;54:11:55"}
share|improve this answer
Your result gives a 3 x 2 list. We need a list of 3 strings. Hot Pink;53:09:44 Dark Cyan;19:06:42 Lime;54:11:55 hp – Hp Radojewski Schäfer Von Dec 21 '12 at 11:44
@HP Please see edit. Nasser: I hope you don't mind that I added the general case to your answer instead of creating a new one. It fits in nicely I think. I you feel otherwise, please don't hesitate to roll back. – István Zachar Jan 5 at 10:21
OK. . .Your function works well. . .It could not improve in timing compared to the algorithmic one shown below. – Hp Radojewski Schäfer Von Jan 7 at 7:56
Have an other look. It seems not to get the last words. . .If you do {m, n}={1, 4} – Hp Radojewski Schäfer Von Jan 9 at 17:01

A solution was developed. Building a program working on two Streams. One record by one record.

instr = OpenRead[infile];
outstr = OpenAppend[outfile];
azr=3; (* number of records to work on *)
abw=2; (* first word in record to extract *)
azw=2; (* number of words to extract *)
delim=";" (* separator char *)

Do[rean = Read[instr, "Record", NullWords -> True];
arean = rean <> delim;
pos = Flatten[StringPosition[arean, delim]];
fla = Flatten[{0, Drop[pos, {1, Length[pos], 2}]}];
extract = StringTake[arean, {fla[[abw]] + 1, fla[[abw + azw]] - 1}];
WriteString[outstr, extract, "\n"],
{i, azr}]; // Timing

It is a kind of ugly. Could not find a function solution.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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