Split Python List by Nth Item

This has been one of the processes I’ve normally not solved in a clean or readable way.

In []: a = [1,2,3,4,5,6,7,8]

Taking the top output I want to return something similar to below.

Out[]: [(1, 2), (3, 4), (5, 6), (7, 8)]

Using a Pythonic approach this task isn’t to difficult, but there is some explaining to do.

First lets look at the code:

In []: a = iter([1,2,3,4,5,6,7,8])

In []: [ i for i in zip(a, a) ]
Out[]: [(1, 2), (3, 4), (5, 6), (7, 8)]

First we need to pass our list to the iter function, this turns our list into a iterator object:

In []: a
Out[]: <listiterator at 0x1037c3110>

This iterator can be used like any other iterator as it has a next method:

In []: a = iter([1,2,3,4,5,6,7,8])

In []: a.next()
Out[]: 1

In []: a.next()
Out[]: 2

In []: a.next()
Out[]: 3

The next bit to understand is the zip function:

In []: a = [1,2,3,4]

In []: b = [5,6,7,8]

In []: zip(a, b)
Out[]: [(1, 5), (2, 6), (3, 7), (4, 8)]

What zip does is takes the 1st object (next method) from each iterator-able object passed in
and packs them together in a tuple, it then continues till one or all objects throws a StopIteration :

In []: a = iter([1,2])

In []: a.next()
Out[]: 1

In []: a.next()
Out[]: 2

In []: a.next()
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-52-aa817a57a973> in <module>()
----> 1 a.next()

StopIteration:

So to put it all together zip takes our ‘a’ variable (an iter object of our list) as a argument twice.

[ i for i in zip(a, a) ]

Zip then grabs the first item from our first argument using the next method, and the first item from our second argument using the next method and bundles them in a tuple. If we were to do this by hand it would look like this:

In []: a = iter([1,2,3,4,5,6,7,8])

In []: first = a.next()

In []: second = a.next()

In []: first, second
Out[]: (1, 2)

Then if we were to do it again:

In []: first = a.next()

In []: second = a.next()

In []: first, second
Out[]: (3, 4)

Hopefully this makes sense now.


Share on Facebook Share on Twitter Share on Google+

Linux /proc/net/route addresses unreadable

So you may have looked at /proc/net/route before and thought how the heck am I suppose to read this. Well here is the low down.

This file uses endianness to store the addresses as hexadecimal,
in reverse; for example 192 as hex is C0:

In []: hex(192)
Out[]: '0xc0'

So lets take a look at our route file:

Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask            MTU     Window  IRTT
eth0    00087F0A        00000000        0001    0       0       0       00FFFFFF        0       0       0
eth0    0000FEA9        00000000        0001    0       0       1002    0000FFFF        0       0       0
eth0    00000000        01087F0A        0003    0       0       0       00000000        0       0       0

Now the first entry has a destination of 00087F0A, lets go ahead and chunk these in to hex
characters:

In []: x = iter('00087F0A')

In []: res = [ ''.join(i) for i in zip(x, x) ]

In []: res
Out[]: ['00', '08', '7F', '0A']

Now if we wanted we could convert these hex codes manually:

In []: int('0A', 16)
Out[]: 10

But we want to do this in one big swoop:

In []: d = [ str(int(i, 16)) for i in res ]

In []: d
Out[]: ['0', '8', '127', '10']

And there we go, our IP address; however, it appears to be backwards. Lets go ahead and fix that, and return as a string:

In []: '.'.join(d[::-1])
Out[]: '10.127.8.0'

And there we have it! Your function may look something like this when all said and done:

In []: def hex_to_ip(hexaddr):
   ....:     x = iter(hexaddr)
   ....:     res = [str(int(''.join(i), 16)) for i in zip(x, x)]
   ....:     return '.'.join(res[::-1])
   ....:

And with output like so:

In []: hex_to_ip('00087F0A')
Out[]: '10.127.8.0'

In []: hex_to_ip('0000FEA9')
Out[]: '169.254.0.0'

Share on Facebook Share on Twitter Share on Google+