Setting order in Dictionary - python

I am a beginner in Python . dont know how can i set the order in Dictionary? . i searched and came to know it could be done through from collections import OrderedDict but don't know how to use it. i am trying below mention code to compare two Dictionary but i am not getting the output in order .
d = { k[0]: k[1:] for k in a }
d2= { k[0]: k[1:] for k in b }
p = {i:j for i,j in d2.items() if i not in d}
q = {i:j for i,j in d.items() if i not in d2}
Any idea how to do this ?
Updated Question :
i have a nested list . How to get each list of nested list in next line ?
[['Eth116/1/12 sales connected 1 full 10G Fabric Exte'], ['Eth116/1/13 marketing connected 190 full 100 ']]
Expected Output :
Eth116/1/12 sales connected 1 full 10G Fabric Exte
Eth116/1/13 marketing connected 190 full 100

Dictionaries are unordered and there is not much you can do to change that, short of writing your own subclass of dict (not recommended). Using OrderedDict will work, as shown in hiro protagonists's comment, as long as you keep in mind that the order in an OrderedDict is the order of insertion and is not related to the values of the keys. (The same is true of the ordering of Python 3 dicts.) If a and b have the same elements but in a different order then the resulting OrderedDicts will not be equal, unless you sort a and b beforehand.
If you want to compare two dicts where you can't easily determine the order of insertion, you need a data structure that supports unordered comparisons. I didn't have your data so I had to make some up. I started with this input
>>> a
[[1, 3, 5, 7, 9], [4, 9, 14, 19, 24, 29, 34, 39], [8, 17, 26, 35, 44, 53, 62, 71], [9, 19, 29, 39, 49, 59, 69, 79, 89]]
>>> b
[[1, 3, 5, 7, 9], [4, 9, 14, 19, 24, 29, 34, 39], [8, 17, 26, 35, 44, 53, 62, 71]]
As you can see, a has one extra element beginning 9.
Modify your dictionary construction code to make the values tuples not lists, because the dict values need to be hashable for the next step to work:
>>> d = { k[0]: tuple(k[1:]) for k in a }
>>> d2= { k[0]: tuple(k[1:]) for k in b }
Then you can convert the dictionaries to sets to do an unordered comparison:
>>> s = set(d.items())
>>> s2 = set(d2.items())
>>> s == s2
False
And you can use the set operators to discover what the difference is:
>>> s2 <= s
True
>>> s - s2
set([(9, (19, 29, 39, 49, 59, 69, 79, 89))])

As of python 3.6 dictionaries are ordered in python, ignore the above answer for pythons above that number!
see here, on stackoverflow

Related

C++: Find minimum in array only among elements with specified indices

I couldn't find a solution to the following problem:
I am trying to find the minimum in a C++ array, but without looking at all elements inside, only among elements that have a specified index.
E.g., if I am given an index k, and an array int* mylist = int[n], then I want to look for the minimal element in mylist only in a "sublist" of elements, where e.g. the index of the respective elements i fulfills i%n = k.
In Python, this can be easily solved by
min([mylist[i] for i in range(n) if i%n==k]),
but afaik, there is no equivalent in C++. Also, lambda functions do not do the trick, as far as I understood.
Any idea how to do this efficiently? Any advice would be appreciated!
This is an example of why standard algorithms work with iterators rather than directly with containers/collections. It allows you to write an iterator that embodies the indices you care about.
The problem is that writing an iterator is more work than most people would like, or consider justified for this simple of a task. Boost has some utilities to make it easier to implement iterators, such as a filter iterator, but as far as I know these are applied based only on the content of the collection, not the indices.
The code involved in creating an index_filter would be fairly trivial (e.g., should be easy to extrapolate from the code for filter_iterator linked above), but there's more boiler-plate there than most people would like. Unless you're doing things like this pretty regularly, it may be difficult to justify.
With range-v3, you may do something similar to:
for (auto e : v | ranges::view::drop(3) | ranges::view::stride(5)) {
std::cout << e << std::endl;
}
so you iterate over index 5 * k + 3.
And you can call ranges::min_element on resulting view:
auto view = v | ranges::view::drop(3) | ranges::view::stride(5);
auto it = ranges::min_element(view);
std::cout << *it << std::endl;
Demo
i % n = k will be a either:
k if k < n
[] empty that is, if k > n
This is because i varies from 0 to n
Hence there will be only one or no elements.
For clarity: n = 50; print([i%n for i in range(n)]) , gives:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49]
That is, unique values between 0 to n-1

Alternate for range in python

If I have to generate natural numbers, I can use 'range' as follows:
list(range(5))
[0, 1, 2, 3, 4]
Is there any way to achieve this without using range function or looping?
You could use recursion to print first n natural numbers
def printNos(n):
if n > 0:
printNos(n-1)
print n
printNos(100)
Based on Nihal's solution, but returns a list instead:
def recursive_range(n):
if n == 0:
return []
return recursive_range(n-1) + [n-1]
Looping will be required in some form or another to generate a list of numbers, whether you do it yourself, use library functions, or use recursive methods.
If you're not opposed to looping in principle (but just don't want to implement it yourself), there are many practical and esoteric ways to do it (a number have been mentioned here already).
A similar question was posted here: How to fill a list. Although it has interesting solutions, they're all still looping, or using range type functions.
Well, yes, you can do this without using range, loop or recursion:
>>> num = 10
>>> from subprocess import call
>>> call(["seq", str(num)])
You can even have a list (or a generator, of course):
>>> num = 10
>>> from subprocess import check_output
>>> ls = check_output(["seq", str(num)])
>>> [int(num) for num in ls[:-1].split('\n')]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42]
But...what's the purpose?

I want to randomly select items from a list and add them to another list without replacement

I'm trying to randomly select items from a list and add them to another list.
The list of elements I'm choosing from looks like this:
data=[2,3,4,7,8,12,17,24,27,33,35,36,37,38,40,43,44,50,51,54]
I want to randomly take an element from this list and add it to one of four lists until each list has the same number of elements.
lists=[[1,'x','x','x','x','x'],[3,'x','x','x','x','x'],[5,'x','x','x','x','x'],[7,'x','x','x','x','x']]
I have tried using random.choice but this gives me duplicates:
def fill_lists(data):
for list in lists:
for n,i in enumerate(list):
if i=='x':
list[n]= random.choice(data)
I want my function to return a list that contains 4 lists each containing a random sample of the data list with no duplicates. I also want the first element of each list to be a value that I have already placed into the list.
import random
data=[2,3,4,7,8,12,17,24,27,33,35,36,37,38,40,43,44,50,51,54]
random.shuffle(data)
lists = [data[i:i+len(data)/4] for i in range(0, len(data), len(data)/4)]
print(lists)
Randomly pulling from your initial list will have the same effect as shuffling then pulling in order. Splitting into sublists can then be done. If you need the sublists sorted, just map sort over the list afterwards.
You can change the number of groups by altering the divisor of len(data)/4
Edit: I missed this part of your question:
heads = [1,3,5,7]
[q.insert(0,p) for p,q in zip(heads,lists)]
You can use random.sample:
data=[2,3,4,7,8,12,17,24,27,33,35,36,37,38,40,43,44,50,51,54]
random.sample(data, 5)
# [27, 12, 33, 24, 17]
To get a nested list of it, use a list comprehension
[random.sample(data, 5) for _ in range(5)]
# [[40, 35, 24, 54, 17],
# [17, 54, 35, 43, 37],
# [40, 4, 43, 33, 44],
# [51, 37, 35, 33, 8],
# [54, 4, 44, 27, 50]]
Edit: The above won't give you unique values; you should accept the above answer for the unique values. I interpreted the question wrong!
another shuffle based but ensuring the all sub lists have the same size in case number of elements is not divisible to number of lists (try 7 for example).
from random import shuffle
def split(data, n):
size=int(len(data)/n);
for i in range(0, n*size, size):
yield data[i:i+size]
data=[2,3,4,7,8,12,17,24,27,33,35,36,37,38,40,43,44,50,51,54]
shuffle(data)
list(split(data, 5))
You could try this, modifying the ranges inside the d function to tune to the number elements you want.
import random
def f(data):
val = random.choice(data)
ix = data.index(val)
data.pop(ix)
return val, data
def d(data):
topholder = []
m = len(data)/4
for i in range(4):
holder = []
for n in range(m):
holder.append(f(data)[0])
topholder.append(holder)
return topholder
d(data)
This will always give you 4 lists of randomly sampled values without duplication.
This is a dynamic function that returns a list of list where each list starts with a specified value. The amount of nested lists is determined by the amount of starting_values.
import random
def get_random_list(element_list, starting_values, size_per_group):
num_of_groups = len(starting_values)
size_per_group -= 1
total_elements = num_of_groups * size_per_group
random_data = random.sample(element_list, total_elements)
return [[starting_values[x]] + random_data[x * size_per_group:(x + 1) * size_per_group] for x in range(num_of_groups)]
data = [2, 3, 4, 7, 8, 12, 17, 24, 27, 33, 35, 36, 37, 38, 40, 43, 44, 50, 51, 54]
print(get_random_list(data, starting_values=[1, 2, 3, 4, 5, 6], size_per_group=2))
# OUTPUT: [[1, 36], [2, 54], [3, 17], [4, 7], [5, 35], [6, 33]]
print(get_random_list(data, starting_values=[9, 3, 5], size_per_group=6))
# OUTPUT: [[9, 54, 2, 7, 38, 24], [3, 35, 8, 37, 40, 17], [5, 44, 4, 27, 50, 3]]
It works for Python2.x and Python3.x but for Python2.x you should change range() to xrange() for better use of memory.

Python: Partial sum of numbers [duplicate]

This question already has answers here:
How to find the cumulative sum of numbers in a list?
(25 answers)
Closed 8 years ago.
can you help me with code which returns partial sum of numbers in text file?
I must import text file, then make a code for partial sums without tools ..etc.
My input:
4
13
23
21
11
The output should be (without brackets or commas):
4
17
40
61
72
I was trying to make code in python, but could only do total sum and not partial one.
If i use the += operator for generator, it gives me an error!
Well, since everyone seems to be giving their favourite idiom for solving the problem, how about itertools.accumulate in Python 3:
>>> import itertools
>>> nums = [4, 13, 23, 21, 11]
>>> list(itertools.accumulate(nums))
[4, 17, 40, 61, 72]
There are a number of ways to create your sequence of partial sums. I think the most elegant is to use a generator.
def partial_sums(iterable):
total = 0
for i in iterable:
total += i
yield total
You can run it like this:
nums = [4, 13, 23, 21, 11]
sums = list(partial_sums(nums)) # [ 4, 17, 40, 61, 72]
Edit To read the data values from your file, you can use another generator, and chain them together. Here's how I'd do it:
with open("filename.in") as f_in:
# Sums generator that "feeds" from a generator expression that reads the file
sums = partial_sums(int(line) for line in f_in)
# Do output:
for value in sums:
print(value)
# If you need to write to a file, comment the loop above and uncomment this:
# with open("filename.out", "w") as f_out:
# f_out.writelines("%d\n" % value for value in sums)
numpy.cumsum will do what you want.
If you're not using numpy, you can write your own.
def cumsum(i):
s = 0
for elt in i:
s += elt
yield s
try this:
import numpy as np
input = [ 4, 13, 23, 21, 11 ]
output = []
output.append(input[0])
for i in np.arange(1,len(input)):
output.append(input[i] + input[i-1])
print output
Use cumulative sum in numpy:
import numpy as np
input = np.array([4, 13, 23, 21 ,11])
output = input.cumsum()
Result:
print output
>>>array([ 4, 17, 40, 61, 72])
Or if you need a list, you may convert output to list:
output = list(output)
print output
>>>[4, 17, 40, 61, 72]
This is an alternative solution using reduce:
nums = [4, 13, 23, 21, 11]
partial_sum = lambda a, b: a + [a[-1] + b]
sums = reduce(partial_sum, nums[1:], nums[0:1])
Pluses in lambda are not the same operator, the first one is list concatenation and the second one is sum of two integers. Altough Blckknght's may be more clear, this one is shorter and works in Python 2.7.
something like this:
>>> lst = [4, 13, 23, 21 ,11]
>>> [sum(lst[:i+1]) for i, x in enumerate(lst)]
[4, 17, 40, 61, 72]

add two lists then sort = None(?) [duplicate]

This question already has answers here:
Why do these list methods (append, sort, extend, remove, clear, reverse) return None rather than the resulting list?
(6 answers)
Closed 6 months ago.
Second list squared each item on list, xs. Running the code below, python gives me 'None'
xs = [12, 10, 32, 3, 66, 17, 42, 99, 20]
a = [b**2 for b in xs]
c = (a + xs).sort()
print(c, end=', ')
Same list but different code--
xs = [12, 10, 32, 3, 66, 17, 42, 99, 20]
a = [b**2 for b in xs]
c = a + xs
c.sort()
print(c, end=', ')
...python gives me my list(c), all sorted. I don't get it. Or is there a more pythonic way to do this?
Thanks!
Generally speaking, anything that operates on something in-place will return None, by convention. (This convention is not necessarily always followed, however.) somelist.sort() will sort the list in-place.
If you'd rather have a sorted copy, you can just call c = sorted(a + xs). sorted operates on a copy of the original, and therefore returns the copy.
There's a much more through explanation here: http://wiki.python.org/moin/HowTo/Sorting/
You use generator expressions and itertools to reduce the amount of temporary storage like this
>>> import itertools
>>> xs = [12, 10, 32, 3, 66, 17, 42, 99, 20]
>>> a = (b**2 for b in xs)
>>> c = sorted(itertools.chain(a, xs))
>>> c
[3, 9, 10, 12, 17, 20, 32, 42, 66, 99, 100, 144, 289, 400, 1024, 1764, 4356, 9801]

Categories