0

I apologize if this is an oddly presented question. I'm having difficulty trying to specifically nail down how to frame this challenge in python and ultimately incorporated into snakemake.

Lets say we have a few list of elements that correspond to files:

gp1 = ["a", "b", "c"]
gp2 = ["x", "y", "z"]

And we have a previous list that names all elements

all = ["a", "b", "c", "x", "y", "z"]

for each "gp#" list I would like to create a new set of lists that represents said element, i.e for gp1 the result would be 3 lists as follows:

gpa = ["a", "b", "c"]
gpb = ["a", "b", "c"]
gpc = ["a", "b", "c"]

and we would have the equivalent for gp2

gpx = ["x", "y", "z"]
gpy = ["x", "y", "z"]
gpz = ["x", "y", "z"]

With these lists in hand I can then use all as a wildcard and do something like:

mkdir {all} #generate a directory for each element
cp gp{all} {all} #copy the files associated with the elements from each list into each respective corresponding directory

(i.e this would be the "shell/run" portion of two snakemake rules at some point).

This would result in a directory structure as follows:

a
|_a
|_b
|_c
b
|_a
|_b
|_c
c       
|_a
|_b
|_c 
x       
|_x
|_y
|_z
y      
|_x
|_y
|_z
z      
|_x
|_y
|_z

Again apologies if this is confusing and I'm happy to clarify as comments come in. I'm having a difficult time conceptualizing how to approach this.

JonSG
  • 10,542
  • 2
  • 25
  • 36
Dvik
  • 47
  • 4
  • Don't try to create names dynamically. It can be done, but it's a bad practice; use a dictionary instead. See [How do I create variable variables?](https://stackoverflow.com/questions/1373164/how-do-i-create-variable-variables). – Ignatius Reilly Feb 09 '23 at 17:08
  • Thank for the edit! Ok, I think this might be the solution. Can you come up with an example using the above that would achieve this? I'll try on my end too, but I'm inexperienced so will probably take me a while to uderstand – Dvik Feb 09 '23 at 17:27
  • Also, please avoid naming your variable `all`. [`all()`](https://docs.python.org/3/library/functions.html#all) is a Python built-in function. Following PEP8 you can use `all_` instead – euronion Feb 10 '23 at 08:58
  • @euronion Got it. Will avoid it in future asks. I'm not actually using this variable name in irl, just as an example here, but I can see how that would confuse the issue. Thanks! – Dvik Feb 10 '23 at 17:04

1 Answers1

1

A dictionary is the best way of dynamically creating variable names, since the names that are semantically related are stored together. Otherwise, you'll have to find all these variables from within the lot of other globals you may have.

For your case, this may work:

gp1_dict = {"gp" + gp1[i] : gp1 for i in range(len(gp1))}
gp2_dict = {"gp" + gp2[i] : gp2 for i in range(len(gp2))}

print(gp1_dict)
print(gp2_dict)

# Outputs:
# {'gpa': ['a', 'b', 'c'], 'gpb': ['a', 'b', 'c'], 'gpc': ['a', 'b', 'c']}
# {'gpx': ['x', 'y', 'z'], 'gpy': ['x', 'y', 'z'], 'gpz': ['x', 'y', 'z']}

So now I can refer to each list with it's key name, i.e.:

print(gp1_dict["gpa"])
print(gp2_dict["gpx"])

# Outputs
# ['a', 'b', 'c']
# ['x', 'y', 'z']

If there's gp1, gp2, gp3... etc, if you have those in an iterable (a list for example), you can create a dictionary of dictionaries just following the same idea.

Also, if the values in each list are not duplicated between lists, maybe you may want a single dictionary (note that the order in the fors in the comprehension syntax follows the same order that if you were to write nested loops):

gps = [gp1, gp2]
gps_dict = {"gp" + gp_x[i] : gp_x for gp_x in gps for i in range(len(gp_x))}

print(gps_dict['gpa'])
print(gps_dict['gpx'])

# Outputs
# ['a', 'b', 'c']
# ['x', 'y', 'z']

And you can easily iterate all the names, for example:

for key in gps_dict.keys():
    print(key)

# Outputs

# gpa
# gpb
# gpc
# gpx
# gpy
# gpz
Ignatius Reilly
  • 1,594
  • 2
  • 6
  • 15
  • Excellent! I think this is going to work, now just need to tailor it to my specific challenge, but I think this is going to work. Thanks! Accepting answer. – Dvik Feb 10 '23 at 17:02