1

I have a list of computer nodes called node_names, and I want to find the amount of free ram in each node, and store that in a second list. I then want to combine these lists into a dictionary.

I have:

for i in range(0, number_of_nodes):
    sys_output = [commands.getoutput('ssh %s \'free -m\'' % node_names[i])]
    free_memory = [x.split()[9] for x in sys_output]
    print free_memory

For 4 nodes, this returns [mem1],[mem2],[mem3],[mem4].

How can I combine each memory value into a single list? I'm having difficulty assigning free_memory as a list instead of a string which is replaced after each loop iteration.

Once I have a memory list, I should be able to combine it with the node_names list to make a dictionary file and do any necessary sorting.

Krease
  • 15,805
  • 8
  • 54
  • 86
keipertk
  • 27
  • 5
  • Where does `memout` come from? Should that be `sys_output`? – korylprince Nov 27 '13 at 03:33
  • And what you want is `[mem1, mem2, mem3, mem4]`? As a list? – educampver Nov 27 '13 at 03:35
  • Yes, I forgot to change the name when trying to slightly clarify the name. I want each mem in a list yes, so I can add it to the node names and have node_name:free_memory for all 4 nodes. – keipertk Nov 27 '13 at 03:35
  • the you should take `free_memory` out and initialize it as an empty list `[]`. Then just add new items like this: `free_memory += [x.split()[9] for x in sys_output]` – educampver Nov 27 '13 at 03:39

1 Answers1

2

I would recommend just building the dictionary directly:

import commands

node_free_mem = {}

for n in node_names:
    sys_output = commands.getoutput("ssh %s 'free -m'" % n)
    free_memory = sys_output.split()[9]
    node_free_mem[n] = int(free_memory)

Here's code that does exactly what you asked: it builds a list, then uses the list to make a dictionary. Discussion after the code.

import commands

def get_free_mem(node_name):
    sys_output = commands.getoutput('ssh %s \'free -m\'' % node_name)
    free_memory = sys_output.split()[9]
    return int(free_memory)

free_list = [get_free_mem(n) for n in node_names]
node_free_mem = dict(zip(node_names, free_list))

Note that in both code samples I simply iterate over the list of node names, rather than using a range() to get index numbers and indexing the list. It's simplest and best in Python to just ask for what you want: you want the names, so ask for those.

I made a helper function for the code to get free memory. Then a simple list comprehension builds a parallel list of free memory values.

The only tricky bit is building the dict. This use of zip() is actually pretty common in Python and is discussed here:

Map two lists into a dictionary in Python

For large lists in Python 2.x you might want to use itertools.izip() instead of the built-in zip(), but in Python 3.x you just use the built-in zip().

EDIT: cleaned up the code; it should work now.

commands.getoutput() returns a string. There is no need to package up the string inside a list, so I removed the square braces. Then in turn there is no need for a list comprehension to get out the free_memory value; just split the string. Now we have a simple string that may be passed to int() to convert to integer.

Community
  • 1
  • 1
steveha
  • 74,789
  • 21
  • 92
  • 117
  • This is extremely helpful and much appreciated. I'm having only one issue at the line: node_free_mem[n] = int(free_memory) "int() argument must be a string or a number, not 'list'" Is there some other way to force these entries to be integers? – keipertk Nov 27 '13 at 03:48
  • Sorry about that. I should have tested the code. I'll edit it to make it correct. – steveha Nov 27 '13 at 03:53