Victor
Victor

Reputation: 23922

How can I store a list of number inside a number in Python?

I need to save a tuple of 4 numbers inside a column that only accepts numbers (int or floats)

I have a list of 4 number like -0.0123445552, -29394.2393339, 0.299393333, 0.00002345556.

How can I "store" all these numbers inside a number and be able to retrieve the original tuple in Python?

Thanks

Upvotes: 2

Views: 159

Answers (5)

unutbu
unutbu

Reputation: 879341

Following up on @YevgenYampolskiy's idea of using numpy:

You could use numpy to convert the numbers to 16-bit floats, and then view the array as one 64-bit int:

import numpy as np

data = np.array((-0.0123445552, -29394.2393339, 0.299393333, 0.00002345556))

stored_int = data.astype('float16').view('int64')[0]
print(stored_int)
# 110959187158999634

recovered = np.array([stored_int], dtype='int64').view('float16')
print(recovered)
# [ -1.23443604e-02  -2.93920000e+04   2.99316406e-01   2.34842300e-05]

Note: This requires numpy version 1.6 or better, as this was the first version to support 16-bit floats.

Upvotes: 3

Yevgen Yampolskiy
Yevgen Yampolskiy

Reputation: 7190

You can combine 4 integers into a single integer, or two floats into a double using struct module:

from struct import *
s = pack('hhhh', 1, -2, 3,-4)
i = unpack('Q', pack('Q', i[0]))
print i
print unpack('hhhh', s)

s = pack('ff', 1.12, -2.32)
f = unpack('d', s)
print f
print unpack('ff', pack('d', f[0]))

prints

(18445618190982447105L,)
(1, -2, 3, -4)
(-5.119999879002571,)
(1.1200000047683716, -2.319999933242798)

Basically in this example tuple (1,-2,3,-4) gets packed into an integer 18445618190982447105, and tuple ( 1.12, -2.32) gets packed into -5.119999879002571

To pack 4 floats into a single float you will need to use half-floats, however this is a problem here:

With half-float it looks like there is no native support in python as of now: http://bugs.python.org/issue11734

However numpy module do have some support for half-floats (http://docs.scipy.org/doc/numpy/user/basics.types.html). Maybe you can use it somehow to pack 4 floats into a single float

Upvotes: 1

namit
namit

Reputation: 6957

my idea is weird; but will it work??

In [31]: nk="-0.0123445552, -29394.2393339, 0.299393333, 0.00002345556"

In [32]: nk1="".join(str(ord(x)) for x in nk)

In [33]: nk1
Out[33]: '454846484950515252535353504432455057515752465051575151515744324846505757515751515151443248464848484850515253535354'

In [34]: import math

In [35]: math.log(long(nk1), 1000)
Out[36]: 37.885954947611985

In [37]: math.pow(1000,_)
Out[37]: 4.548464849505043e+113

you can easily unpack this string(Out[33]); for example split it at 32; its for space.
also this string is very long; we can make it to a small number by math.log; as we got in Out[36].

Upvotes: 0

brabec
brabec

Reputation: 4730

This does not really answer your question, but what you're trying to do violates 1NF. Is changing the DB schema to introduce an intersection table really not an option?

Upvotes: 0

Abhijit
Abhijit

Reputation: 63717

If by int you mean the datatype int in Python (which is unlimited as of the current version), you may use the following solution

>>> x
(-0.0123445552, -29394.2393339, 0.299393333, 2.345556e-05)
>>> def encode(data):
    sz_data = str(data)
    import base64
    b64_data = base64.b16encode(sz_data)
    int_data = int(b64_data, 16)
    return int_data

>>> encode(x)
7475673073900173755504583442986834619410853148159171975880377161427327210207077083318036472388282266880288275998775936614297529315947984169L
>>> def decode(data):
    int_data = data
    import base64
    hex_data = hex(int_data)[2:].upper()
    if hex_data[-1] == 'L':
        hex_data = hex_data[:-1]
    b64_data = base64.b16decode(hex_data)
    import ast
    sz_data = ast.literal_eval(b64_data)
    return sz_data

>>> decode(encode(x))
(-0.0123445552, -29394.2393339, 0.299393333, 2.345556e-05)

Upvotes: 2

Related Questions