Backspace does not seem to work in python - python

network={1:[2,3,4],2:[1,3,4], 3:[1,2], 4:[1,3,5], 5:[6,7,8], 6:[5,8],7:[5,6], 8:[5,6,7]}
str1='network.csv'
output = open(str1,'w')
for ii1 in network.keys():
output.write(repr(ii1)+":[")
for n in network[ii1]:
output.write(' %s,'%(repr(n)))
output.write('\b'+']\n')
output.close()
What I expect is something like:
1:[ 2, 3, 4]
2:[ 1, 3, 4]
3:[ 1, 2]
4:[ 1, 3, 5]
5:[ 6, 7, 8]
6:[ 5, 8]
7:[ 5, 6]
8:[ 5, 6, 7]
but what I get is:
1:[ 2, 3, 4,]
2:[ 1, 3, 4,]
3:[ 1, 2,]
4:[ 1, 3, 5,]
5:[ 6, 7, 8,]
6:[ 5, 8,]
7:[ 5, 6,]
8:[ 5, 6, 7,]
I am a newbie....could someone please help?

The "\b" simply inserts the ASCII backspace character; it does not remove the just-written character from the output file. This is why your code doesn't behave as you expect.
Now, to fix it you could replace
for ii1 in network.keys():
output.write(repr(ii1)+":[")
for n in network[ii1]:
output.write(' %s,'%(repr(n)))
output.write('\b'+']\n')
with
for ii1 in network.keys():
output.write(repr(ii1)+":[ ")
output.write(", ".join(map(repr, network[ii1])))
output.write(']\n')
or, to improve it further, with
for k, v in network.items():
print >>output, "%s:[ %s]" % (repr(k), ", ".join(map(repr, v)))
Lastly, if the keys are simple integers as your example indicates, then the repr(k) can be simplified to just k. Also, if the values in the dictionary are lists of integers or somesuch, then the entire ", ".join(map(repr, v)) dance might be unnecessary.

Use str.join to generate Comma-Separated-Values, to avoid the need for backspace:
str.join(iterable)
Return a string which is the concatenation of the strings in the iterable iterable. The separator between elements is the string providing this method.
A simpler approach is, for example, list comprehensions iterating over dictionary items:
>>> [output.write("%s:%s\n" % item) for item in network.items()]

Why not to use str(dict)?
for k, v in network.iteritems():
output.write(str({k: v})[1:-1] + '\n')

You can't delete characters written in a file in general.
However, with a little redesigning of your code, you can get this:
network={1:[2,3,4],2:[1,3,4], 3:[1,2], 4:[1,3,5], 5:[6,7,8], 6:[5,8],7:[5,6], 8:[5,6,7]}
str1='network.csv'
output = open(str1,'w')
for ii1 in network.keys():
output.write(repr(ii1)+":[")
first=false
for n in network[ii1]:
if first:
first=false
else:
output.write(',')
output.write('%s'%(repr(n)))
output.write('\b'+']\n')
output.close()

Whether or not the backspace character actually 'backspaces' is probably dependent on the shell you're using.
It is much simpler and easier (and proper) to just output the data yourself as you want it formatted.
network={1:[2,3,4],2:[1,3,4], 3:[1,2], 4:[1,3,5], 5:[6,7,8], 6:[5,8],7:[5,6], 8:[5,6,7]}
output = open('network.csv','w')
for key,values in network.items():
str_values = [str(x) for x in values]
output.write('%s:[%s]' % (key,','.join(str_values))
output.close()

Try this:
network={1:[2,3,4],2:[1,3,4], 3:[1,2], 4:[1,3,5], 5:[6,7,8], 6:[5,8],7:[5,6], 8:[5,6,7]}
str1='network.csv'
with open(str1, 'w') as output:
for ii1 in network.keys():
output.write(repr(ii1)+":[")
output.write(','.join(repr(n) for n in network[ii1]))
output.write(']\n')
Output in network.csv:
1:[2,3,4]
2:[1,3,4]
3:[1,2]
4:[1,3,5]
5:[6,7,8]
6:[5,8]
7:[5,6]
8:[5,6,7]
Some points:
I'm using with ... as ...:. This guarantees that the file will be closed properly.
I'm using ','.join to create the comma-separated list. This is the 'pythonic' way to merge lists (or, more precisely, iterables) of strings.

Related

Python - Counter merges elements from list together

I have a list full of Windows API calls:
listOfSequences =
['GetSystemDirectoryA',
'IsDBCSLeadByte',
'LocalAlloc',
'CreateSemaphoreW',
'CreateSemaphoreA',
'GlobalAddAtomW',
'lstrcpynW',
'LoadLibraryExW',
'SearchPathW',
'CreateFileW',
'CreateFileMappingW',
'MapViewOfFileEx',
'GetSystemMetrics',
'RegisterClipboardFormatW',
'SystemParametersInfoW',
'GetDC',
'GetDeviceCaps',
'ReleaseDC', ...... and so on .....]
Since some of them occurs several times, I wanted to collected their number of occurences. Thus, I used collections.Counter.
But it concatenates some APIs together:
lCountedAPIs = Counter(listOfSequences)
when I print the lCountedAPIs I get the folowing:
Counter({'IsRectEmptyLocalAlloc': 2,
'DdePostAdvise': 3,
'DispatchMessageWGetModuleFileNameA': 2,
'FindResourceExW': 50318,
'ReleaseDCGetModuleFileNameW': 7,
'DefWindowProcAGetThreadLocale': 1,
'CoGetCallContext': 40,
'CoGetTreatAsClassGetCommandLineA': 1,
'GetForegroundWindowGetSystemDirectoryW': 1,
'GetModuleHandleWGetSystemTimeAsFileTime': 2,
'WaitForSingleObjectExIsChild': 1,
'LoadIconAGetWindowsDirectoryW': 2,
'GlobalFreeLocalAlloc': 10,
'GetMapModeCreateSemaphoreW': 1,
'HeapLock': 11494, <---------- A
'CharNextAGetCurrentProcessId': 11, <---------- B
'RemovePropWGetStartupInfoA': 1,
'GetTickCountGetVersionExW': 55,
So for ex.:
HeapLock (see A) was not merged with another API
But CharNextA was concatenated with GetCurrentProcessId (see B)
Can somebody tell me why this happens and how to fix that ?
Thanks in advcance & best regards :)
Check your list definition. Python concatenates adjacent string literals, so you must have missed a comma somewhere in the the middle:
listOfSequences = [
'GetSystemDirectoryA',
'IsDBCSLeadByte',
'LocalAlloc',
...
'CharNextA'
# ^ comma missing here
'GetCurrentProcessId',
...
]
This has bitten me several times.
Nothing in Counter does that. You must necessarily have 11 occurrences of 'CharNextAGetCurrentProcessId' in listOfSequences. You can check this by running 'CharNextAGetCurrentProcessId' in listOfSequences.

Piping a pipe-delimited flat file into python for use in Pandas and Stats

I have searched a lot, but haven't found an answer to this.
I am trying to pipe in a flat file with data and put into something python read and that I can do analysis with (for instance, perform a t-test).
First, I created a simple pipe delimited flat file:
1|2
3|4
4|5
1|6
2|7
3|8
8|9
and saved it as "simpledata".
Then I created a bash script in nano as
#!/usr/bin/env python
import sys
from scipy import stats
A = sys.stdin.read()
print A
paired_sample = stats.ttest_rel(A[:,0],A[:,1])
print "The t-statistic is %.3f and the p-value is %.3f." % paired_sample
Then I save the script as pairedttest.sh and run it as
cat simpledata | pairedttest.sh
The error I get is
TypeError: string indices must be integers, not tuple
Thanks for your help in advance
Are you trying to call this?:
paired_sample = stats.ttest_rel([1,3,4,1,2,3,8], [2,4,5,6,7,8,9])
If so, you can't do it the way you're trying. A is just a string when you read it from stdin, so you can't index it the way you're trying. You need to build the two lists from the string. The most obvious way is like this:
left = []
right = []
for line in A.splitlines():
l, r = line.split("|")
left.append(int(l))
right.append(int(r))
print left
print right
This will output:
[1, 3, 4, 1, 2, 3, 8]
[2, 4, 5, 6, 7, 8, 9]
So you can call stats.ttest_rel(left, right)
Or to be really clever and make a (nearly impossible to read) one-liner out of it:
z = zip(*[map(int, line.split("|")) for line in A.splitlines()])
This will output:
[(1, 3, 4, 1, 2, 3, 8), (2, 4, 5, 6, 7, 8, 9)]
So you can call stats.ttest_rel(*z)

Duplicating Items within a list

I am fairly new to python and am trying to figure out how to duplicate items within a list. I have tried several different things and searched for the answer extensively but always come up with an answer of how to remove duplicate items, and I feel like I am missing something that should be fairly apparent.
I want a list of items to duplicate such as if the list was [1, 4, 7, 10] to be [1, 1, 4, 4, 7, 7, 10, 10]
I know that
list = range(5)
for i in range(len(list)):
list.insert(i+i, i)
print list
will return [0, 0, 1, 1, 2, 2, 3, 3, 4, 4] but this does not work if the items are not in order.
To provide more context I am working with audio as a list, attempting to make the audio slower.
I am working with:
def slower():
left = Audio.getLeft()
right = Audio.getRight()
for i in range(len(left)):
left.insert(????)
right.insert(????)
Where "left" returns a list of items that are the "sounds" in the left headphone and "right" is a list of items that are sounds in the right headphone. Any help would be appreciated. Thanks.
Here is a simple way:
def slower(audio):
return [audio[i//2] for i in range(0,len(audio)*2)]
Something like this works:
>>> list = [1, 32, -45, 12]
>>> for i in range(len(list)):
... list.insert(2*i+1, list[2*i])
...
>>> list
[1, 1, 32, 32, -45, -45, 12, 12]
A few notes:
Don't use list as a variable name.
It's probably cleaner to flatten the list zipped with itself.
e.g.
>>> zip(list,list)
[(1, 1), (-1, -1), (32, 32), (42, 42)]
>>> [x for y in zip(list, list) for x in y]
[1, 1, -1, -1, 32, 32, 42, 42]
Or, you can do this whole thing lazily with itertools:
from itertools import izip, chain
for item in chain.from_iterable(izip(list, list)):
print item
I actually like this method best of all. When I look at the code, it is the one that I immediately know what it is doing (although others may have different opinions on that).
I suppose while I'm at it, I'll just point out that we can do the same thing as above with a generator function:
def multiply_elements(iterable, ntimes=2):
for item in iterable:
for _ in xrange(ntimes):
yield item
And lets face it -- Generators are just a lot of fun. :-)
listOld = [1,4,7,10]
listNew = []
for element in listOld:
listNew.extend([element,element])
This might not be the fastest way but it is pretty compact
a = range(5)
list(reduce(operator.add, zip(a,a)))
a then contains
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4]
a = [0,1,2,3]
list(reduce(lambda x,y: x + y, zip(a,a))) #=> [0,0,1,1,2,2,3,3]

Merge python lists in a specific order/sequence

I'm trying to make two lists of the sort:
list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
into
list_both= ["onetothree",1,2,3,"fourtosix",4,5,6...]
This is just a way to describe my problem. I need to do this with all the elements in list_numbers & list_letters. The number or elements in list_numbers will always be dividable by the amount of elements in list_letters so theres no need to worry about "crooked data".
After searching for a good three hours, trying with many different kinds of "for" and "while" loops and only getting python 2.x questions, bad results and syntax errors, I thought I'd maybe deserve to post this question.
Hacky, but it'll get the job done
>>> list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
>>> list(itertools.chain.from_iterable(zip(list_letters, *zip(*[list_numbers[i:i+3] for i in range(0, len(list_numbers), 3)]))))
['onetothree', 1, 2, 3, 'fourtosix', 4, 5, 6, 'seventonine', 7, 8, 9, 'tentotwelve', 10, 11, 12]
Or, the cleaner version:
>>> answer = []
>>> i = 0
>>> for letter in list_letters:
... answer.append(letter)
... for j in range(3):
... answer.append(list_numbers[i+j])
... i += j+1
...
>>> answer
['onetothree', 1, 2, 3, 'fourtosix', 4, 5, 6, 'seventonine', 7, 8, 9, 'tentotwelve', 10, 11, 12]
Of course, if you don't have sufficiently many entries in list_numbers, you this will burn you
try this:
list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
list_both=[]
c=1
for n in range(len(list_letters)):
list_both.append(list_letters[n])
list_both[c+n:c+n]=list_numbers[c-1:c+2]
c+=3
print(list_both)

How to write a generator that returns ALL-BUT-LAST items in the iterable in Python?

I asked some similar questions [1, 2] yesterday and got great answers, but I am not yet technically skilled enough to write a generator of such sophistication myself.
How could I write a generator that would raise StopIteration if it's the last item, instead of yielding it?
I am thinking I should somehow ask two values at a time, and see if the 2nd value is StopIteration. If it is, then instead of yielding the first value, I should raise this StopIteration. But somehow I should also remember the 2nd value that I asked if it wasn't StopIteration.
I don't know how to write it myself. Please help.
For example, if the iterable is [1, 2, 3], then the generator should return 1 and 2.
Thanks, Boda Cydo.
[1] How do I modify a generator in Python?
[2] How to determine if the value is ONE-BUT-LAST in a Python generator?
This should do the trick:
def allbutlast(iterable):
it = iter(iterable)
current = it.next()
for i in it:
yield current
current = i
>>> list(allbutlast([1,2,3]))
[1, 2]
This will iterate through the entire list, and return the previous item so the last item is never returned.
Note that calling the above on both [] and [1] will return an empty list.
First off, is a generator really needed? This sounds like the perfect job for Python’s slices syntax:
result = my_range[ : -1]
I.e.: take a range form the first item to the one before the last.
the itertools module shows a pairwise() method in its recipes. adapting from this recipe, you can get your generator:
from itertools import *
def n_apart(iterable, n):
a,b = tee(iterable)
for count in range(n):
next(b)
return zip(a,b)
def all_but_n_last(iterable, n):
return (value for value,dummy in n_apart(iterable, n))
the n_apart() function return pairs of values which are n elements apart in the input iterable, ignoring all pairs . all_but_b_last() returns the first value of all pairs, which incidentally ignores the n last elements of the list.
>>> data = range(10)
>>> list(data)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(n_apart(data,3))
[(0, 3), (1, 4), (2, 5), (3, 6), (4, 7), (5, 8), (6, 9)]
>>> list(all_but_n_last(data,3))
[0, 1, 2, 3, 4, 5, 6]
>>>
>>> list(all_but_n_last(data,1))
[0, 1, 2, 3, 4, 5, 6, 7, 8]
The more_itertools project has a tool that emulates itertools.islice with support for negative indices:
import more_itertools as mit
list(mit.islice_extended([1, 2, 3], None, -1))
# [1, 2]
gen = (x for x in iterable[:-1])

Categories

Resources