Group Abstract Group Abstract

Message Boards Message Boards

0
|
7.3K Views
|
11 Replies
|
3 Total Likes
View groups...
Share
Share this post:

Create named empty lists, name coming from another list?

Posted 7 years ago
POSTED BY: Paul Cleary
11 Replies
Posted 7 years ago
POSTED BY: Paul Cleary

Paul,

The suggestions you have gotten so far have all been all excellent. I will add one more idea in the mix in case it might better suit your problem.

I like to use the assignments in MMA to make a dictionary. For example, you can enter

junk["one"] = {12}
junk["two"] = {4,8}

You can see all of your assignments with ?junk or Definition[junk] or programmatically with DownValues[junk].

The advantage is that you do not need to create new symbols manually or manage them. Using Marco's example (but making a string out of it since I think you said you are handling large strings)

Set up some lists:

In[6]:= names = RandomSample[WordList[], 10]

Out[6]= {"steps", "highlight", "puppeteer", "cleanness", \
"credential", "nonstarter", "ablaze", "telegraphically", "stoppage", \
"heads"}

In[7]:= tableentries = 
 Table[StringRiffle[RandomChoice[names, 4], " "], 20]

Out[7]= {"cleanness cleanness ablaze heads", "telegraphically \
nonstarter credential credential", "cleanness credential \
telegraphically stoppage", "stoppage heads heads telegraphically", \
"puppeteer ablaze nonstarter telegraphically", "telegraphically \
stoppage credential nonstarter", "telegraphically steps ablaze \
cleanness", "credential stoppage ablaze credential", "heads \
nonstarter puppeteer stoppage", "cleanness ablaze highlight \
cleanness", "ablaze heads nonstarter highlight", "ablaze nonstarter \
heads heads", "stoppage nonstarter steps heads", "cleanness cleanness \
ablaze telegraphically", "nonstarter telegraphically credential \
stoppage", "ablaze puppeteer nonstarter cleanness", "highlight ablaze \
cleanness cleanness", "puppeteer cleanness puppeteer ablaze", \
"stoppage nonstarter stoppage highlight", "credential heads \
credential ablaze"}

To create the dictionary programmatically create a function to assign the dictionary value, testing if its the first time it is used -- either set the first value or just append the latest value.

tmpify[x_String, val_] := 
 If[Head[tmp[x]] === tmp, tmp[x] = {val}, 
  tmp[x]  = Append[tmp[x], val]]

Now you can use it by first clearing all old entries in tmp and then mapping the function over the table of values and Map it a second time over the list of names to give the location of every name in every string in the table:

Clear[tmp]

Map[Function[name, 
   MapIndexed[
    If[StringCount[#1, ___ ~~ name ~~ ___] > 0, tmpify[name, #2[[1]]],
       Nothing] &, tableentries]], names];

This is the result:

enter image description here

This approach would be very fast when doing many lists and it would be easy to reference the result either with

tmp["steps"]

or

tmp[names[[1]]]

I hope this helps.

Regards,

Neil

POSTED BY: Neil Singer

Summing up the linked topic:

ToExpression[
  # <> "temp"
, StandardForm
, Function[symbol, symbol = {}, HoldAll]
]&  /@ {"one", "bus", "tree", "townhouse"}
POSTED BY: Kuba Podkalicki
Posted 7 years ago

Dear Marco

Before I turned in last night I had almost solved the problem, I had arrived at this

nametemp = Table["{}", {i, 1, Length[namestally]}]

which as you already know creates a named list of empty lists. This was perfect as I could then access each list by it's index, it wasn't necessary for it to have any name as the index number was associated to the names elsewhere. This also meant I didn't have to append any temp to anything (this was something I thought I would have to do so there would be no conflict between variable names and the same names elsewhere).

My goal in the end is to write what is called a game parser, when I say write I have already done it but it is very inefficient and slow mainly because I have to scan the full file each time for every mob as they are called, and then do full scans each time for every person (up to 60). I still have to do as many full passes as there are mobs, but each one now has it's data in one of these lists and this sorted data may only contain information relating to 1 to 3 or 4 different people. So to fully parse that mob to see who has done damage to it and how much only requires scanning a file of 100 lines or so up to 4 times which is a huge saving on my previous attempt.

I am reluctant to post any actual data on these forums but if you wished to see exactly what it looks like don't mind emailing you directly a text tile I have a small one with just over 151k lines, a few mb's.

Regards

Paul.

POSTED BY: Paul Cleary

In order to handle cases where those symbols already have values you need to incorporate the third argument of ToExpression, see:

POSTED BY: Kuba Podkalicki
Posted 7 years ago

Thank you for the link Kuba, I look forward to reading it.

POSTED BY: Paul Cleary

Dear Paul,

I am not sure whether the question is about realising it with procedural programming or whether at the end you just want the result. Also, I don't have the data you use. I will make it up according to what I understand. Suppose we have some random words from the dictionary

ClearAll["Global`*"]
names = RandomSample[WordList[], 10]

enter image description here

Now I make a "large" table with 20 lines. I could do millions of course, but it is difficult to post here:

tableentries = Table[RandomChoice[names, 4], 20];
TableForm[tableentries]

enter image description here

We now make a list of as many empty lists as there are "words" and then a list of these words with "temp" appended:

dummy = Table[{}, {i, 1, Length[names]}];
dummynames = ToExpression[# <> "temp"] & /@ names;

Now we can see where the words come up in the large table:

Do[AppendTo[dummy[[#]], k] & /@ Flatten[Position[names, #] & /@ tableentries[[k]]], {k, 1, Length[tableentries]}]

This is still procedural programming, but it is easily changed to functional style. Now we get everything together:

Set @@@ Transpose[{dummynames, dummy}];

Now you can ask for the lists:

degeneratetemp

enter image description here

propertiedtemp

enter image description here

Note that numbers are repeated if the word comes up several times in a row. If you do not need that you can use DeleteDuplicates to clean that up.

I have put in no thought of making this efficient at all. Also, I am only on a mobile device right now so cannot test this as much as I should. In fact, on a single CPU this will take about 15 minutes for 1000000 lines and 6 columns on a single CPU. ParallelDo could make this faster.

On a million lines this runs in about 26 seconds on my machine:

Do[Flatten[Position[MemberQ[#, names[[k]]] & /@ tableentries, True]], {k, 1, Length[names]}]

So, counting millions of lines of code should be quite possible.

Cheers,

Marco

POSTED BY: Marco Thiel
Posted 7 years ago

Dear Marco

I appreciate your time on this and indeed we are getting closer to my goal, those list's are created as you say and I can append to them by specifically writing into them, but my goal is to add into each list many thousands of lines of text that is parsed from a much bigger list where some lines of text contains the name of the created list. (if you see what I mean). Secondly there could be up to 60 of these created named lists, non of which I need to know the names of nor do I want to see them and I want it to be all automatic. So in a nutshell I have a large file consisting of multiple millions of lines of text, within these lines of text are anywhere from 1 to 60 names, the names can be extracted as they always appear at a certain position in the line and this forms the basis of my named list. I now want to create as many empty lists as there are names and on the second pass through the large file extract only those lines that contain the name and put it in the newly created temp list so at the end of the second pass each of the lists say onetemp now contains only those line that also contain one (one is a bad example I know) the names would be actual names of characters. So I need to be able to index the list of lists and then add information into them. Sorry if this is getting long.

Edit

If we add this to the line

nametemp = Map[Set[#, {}] &, ToExpression[# <> "temp"] & /@ names]

I can index nametemp as in nametemp[[1]] and use Reap and Sow and it does seem to work, it seems to add it to what starts as an empty list, yet if you directly type the name of the list it is still empty. Wonder if this is intended?

Cheers,

POSTED BY: Paul Cleary

Dear Paul,

all the lists are in fact created. If you just type

onetemp

you will see that it gives an empty list. If you want to add something to the list you can do:

AppendTo[onetemp,5]

and it will add 5 to that list. If you then execute

onetemp

it will be a list with 5 as the only element. I guess that the output was a bit confusing. You can suppress it with a ; at the and of the line.

Alternatively, this works, but is longer than my original solution:

tempnames = ToExpression[# <> "temp"] & /@ names; 
Do[tempnames[[i]] = {}, {i, 1, Length[names]}]

Also, procedural programming is discouraged.

Cheers,

Marco

POSTED BY: Marco Thiel
Posted 7 years ago

Hi Marco

Thanks for the quick reply, however, it doesn't seem to do what I want, your program creates a list of empty {} . If I want to create a named empty list I would type onetemp={} Then I could access onetemp and add data into it, how would I do that in your example?

POSTED BY: Paul Cleary

Hi,

something like this?

names = {"one", "bus", "tree", "townhouse"};
Map[Set[#, {}] &, ToExpression[# <> "temp"] & /@ names]

Best wishes, Marco

POSTED BY: Marco Thiel
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard