How to print a list of strings using yields - python

could you please tell me how to have the following output using the code below?
Input list:
list_1 = ["A","house","49","apartment","AD","Luke","17","17","Mike","8","B","Eliz","22","www.odeon.com","64", "holidays"]
Code:
def splitting(N):
for i in len(list_name):
yield list_name[i:i + N]
Expected output:
1st group: ["A","house","49","apartment","AD"]
2nd group: ["Luke","17","17","Mike","8"]
3rd group: ["B","Eliz","22","www.odeon.com","64"]
4th group: ["holidays]
I have followed most of the previous questions that have been already published in stackoverflow, but I am still having difficulties. Since it might be a duplicated question, I would like to ask if it would be possible to help me to figure out with this function and the expected output before closing. Most of you have experience with Python: I am a beginner with lots of questions and with the necessity of asking a couple of them to learn more, even by my own mistakes.
Thank you

You can use a for loop with a skip and then yield slices:
list_1 = ["A","house","49","apartment","AD","Luke","17","17","Mike","8","B","Eliz","22","www.odeon.com","64", "holidays"]
def splitting(a_list, N):
for i in range(0, len(a_list), N):
yield a_list[i:i + N]
for item in splitting(list_1, 5):
print(item)
Prints:
['A', 'house', '49', 'apartment', 'AD']
['Luke', '17', '17', 'Mike', '8']
['B', 'Eliz', '22', 'www.odeon.com', '64']
['holidays']

Right now, i is being incremented by one each time. So the second yield will return with ['house', '49', ...] (a total of N items). Instead, you want i to be incremented by N each time. You can accomplish that like this:
def splitting(N):
i = 0
while i < len(list_name) - N:
yield list_name[i:i + N] # while condition prevents IndexError
i = i + N
if i < len(list_name):
yield list_name[i:] # Yield what remains of the list

Related

How to concatenate the list elements

Here I'm having the list of list, i want to concatenate only the first two elements if the second element of list has name. else do nothing.
The below is the code which i tried:
lst_1 = [['ANTWERP' 'BRIDGE', '05', 'N'],
['NORTHERN' 'VIGOUR', '05', 'N'],
['BRIDGE', '98', 'N']]
for i in lst_1:
for j in i:
j[0:2] = ['_'.join(j[0:2])]
expected output:
[['ANTWERP_BRIDGE', '05', 'N'],
['NORTHERN_VIGOUR', '05', 'N'],
['BRIDGE', '98', 'N']]
can i find any way to do this?
I wouldn't over think it, simply just concatenate the elements then add on the rest
[[f"{i[0]}_{i[1]}" if len(i) == 4 else i[0], *i[-2:]] for i in lst_1]
First you need to decide what it means for the second element to be a name. I suggest two possibilities. One is to check the length of the sub-list:
if len(i) == 4:
Another is to check for integers:
if len(i) > 2 and not i[1].isdigit():
In either case, you can merge pretty much as you did before, but with an if instead of the inner for loop:
for i in lst_1:
if <condition>:
i[:2] = ['_'.join(i[:2])]
This modifies lst_1 in-place. If you want to replace it with a new object, use #Sayse's answer.

Get a slice of a sorted list according to a key in Python

Is it possible to slice a sorted list based on some key value (e.g the length of the list items)? If so, how?
For example I get a sorted list like this:
sorted_list = sorted(some_list, key=len)
Now I want to get a slice containing all items with the lowest and equal len (i.e. all items of len: min(sorted_list, key=len) ) which should be the at the head of the sorted list.
You can group the items first, then take the elements of the first resulting subiterator.
from itertools import groupby
firsts = list(next(groupby(sorted(some_list, key=len), len))[1])
For example,
>>> some_list = [[1, 2, 3], [4, 5, 6], [1], [2], [2, 3]]
>>> list(next(groupby(sorted(some_list, key=len), len))[1])
[[1], [2]]
You can do it like this:
min_len = len(min(some_list, key=len))
sorted_list = sorted((x for x in some_list if len(x) == min_len), key=len)
What this does is it finds the length of the minimum element in the list, and then filters out the elements that are longer than that when the list is passed into the sorted function. It requires an extra pass over the data to find the min length, but sorting takes much longer than that, so that time-cost is practically irrelevant.
This function sorts the list, gets the key (i.e. the shortest length element), then builds an array containing only elements of equal length.
def slice_list(lst, func=len):
# start by sorting the list
sorted_lst = sorted(lst, key=func)
# get the key
key = func(sorted_lst[0])
# get the slice
slice = [v for v in sorted_lst if func(v) <= key]
return slice
Since there are no test cases, here is one (if I am interpreting this question correctly)
test = ['abcd', 'abcde', 'efgh', '1234', 'abcdef']
print(slice_list(test, len))
Outputs
['abcd', 'efgh', '1234']
This is more for curiosity than practicality (since itertools is really performant)…you can group by a minimum and avoid the sort in a single pass in the same way you can find the minimum of a list without sorting. Here you just keep track of the current minimum and all the values of the same size. If you find a smaller value scrap the old ones and start again:
some_list = ['999', '11', '22', '343', '12', '545', '99', '11', '100', '11']
def minGroup(l, f):
it = iter(l)
current = [next(it)]
curr_min = f(current[0])
for item in it:
if f(item) < curr_min:
curr_min, current = f(item), [item]
elif f(item) == curr_min:
current.append(item)
return current
minGroup(some_list, len)
# ['11', '22', '12', '99', '11', '11']
minGroup(some_list, int)
# ['11', '11', '11']

Array pagination unknown failure

I was resolving a HackerRank quiz, which consisted in emulating a pagination request.
The function received an array of items, the sort parameter, the sort order, the page number, and the items per page, and returns an array of names corresponding to the given page.
The items had the shape [name: string, relevance: int, price: int].
The sort parameter was 0 for name, 1 for relevance, and 2 for price.
The sort order was 0 for ascending and 1 for descending.
I tried the function in JavaScript and in Python, in case the default sorting function worked different and altered the results. This is my implementation in Python3.
def fetchPaginated(items, sortParameter, sortOrder, pageNum, itemsPerPage):
sortedItems = sorted(items, key=lambda item: item[sortParameter], reverse=False if sortOrder == 0 else True)
paginatedIdx = pageNum * itemsPerPage
slicedItems = sortedItems[paginatedIdx:(paginatedIdx + itemsPerPage)]
return map(lambda item: item[0], slicedItems)
Since HackerRank has hidden test cases, I don't know the inputs for the failing tests. I remember that the size of the array was in the order of the 100s and 1000s, the page number was between 0 and 2, the items per page between 1 and 20. There wasn't a pattern for the sort parameter and order (it wasn't like all the failing tests were for the sort parameter 1 or similar).
Could someone indicate me if my code, or the algorithm behind it has a flaw I don't detect? Maybe a flaw that makes it fail on edge cases?
EDIT:
Link to the HackerRank question. I don't know if it's available to everyone: https://www.hackerrank.com/test/78113p6eaqn
I also had this question on an assessment. The problem is that the input for items is a 2D list of strings, not a list of [name: string, relevance: int, price: int]. Thus when you called sort you were sorting strings of numbers instead of actual numbers, which led to unexpected results. For example:
>>> nums = list(range(1, 6)) + list(range(10, 60, 10))
>>> nums = list(map(str, nums))
>>> nums
['1', '2', '3', '4', '5', '10', '20', '30', '40', '50']
>>> nums.sort()
>>> nums
['1', '10', '2', '20', '3', '30', '4', '40', '5', '50']
A small fix would be to change the key function so that it converts relevance and price (columns 1 and 2) to ints while leaving name (column 0) alone.
sortedItems = sorted(items, key=lambda item: int(item[sortParameter]) if sortParameter else item[sortParameter], reverse=sortOrder)

Del list and next list element in list if string exist

I have an example:
list = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
for i in range(len(list)):
if list[i][-1] == "last":
del(list[i+1])
del(list[i])
I'd like to delete this list where the last item is "last" and the next item on the list.
In this example there is a problem every time - I tried different configurations, replacing with numpy array - nothing helps.
Trackback:
IndexError: list index out of range
I want the final result of this list to be ['3', '4', 'next']
Give me some tips or help how I can solve it.
Try this:
l = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
delete_next = False
to_ret = []
for x in l:
if x[-1] == 'last':
delete_next = True
elif delete_next:
delete_next = False
else:
to_ret.append(x)
Using a variable to store if this needs to be deleted
Loop over the list, if the last element of that iteration == 'last' then skip, else, append to a new list.
Also, it is not recommended to edit lists while iterating over them as strange things can happen, as mentioned in the comments above, like the indexes changing.
l = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
newlist = []
for i in l:
if i[-1] == 'last':
continue
else:
newlist.append(i)

I want a program that writes every possible combination to a different line of a text file

I want to write a program that would print every combination of a set of variables to a text file, creating a word list. Each answer should be written on a separate line and write all of the results for 1 digit, 2 digits, and 3 digits to a single text file.
Is there a simple way I can write a python program that can accomplish this? Here is an example of the output I am expecting when printing all the binary number combinations possible for 1, 2, and 3 digits:
Output:
0
1
00
01
10
11
000
001
010
011
100
101
110
111
A naïve solution which solves the problem and is general enough for any application you might have is this:
def combinations(words, length):
if length == 0:
return []
result = [[word] for word in words]
while length > 1:
new_result = []
for combo in result:
new_result.extend(combo + [word] for word in words)
result = new_result[:]
length -= 1
return result
Basically, this gradually builds up a tree in memory of all the combinations, and then returns them. It is memory-intensive, however, and so is impractical for large-scale combinations.
Another solution for the problem is, indeed, to use counting, but then to transform the numbers generated into a list of words from the wordlist. To do so, we first need a function (called number_to_list()):
def number_to_list(number, words):
list_out = []
while number:
list_out = [number % len(words)] + list_out
number = number // len(words)
return [words[n] for n in list_out]
This is, in fact, a system for converting decimal numbers to other bases. We then write the counting function; this is relatively simple, and will make up the core of the application:
def combinations(words, length):
numbers = xrange(len(words)**length)
for number in numbers:
combo = number_to_list(number, words)
if len(combo) < length:
combo = [words[0]] * (length - len(combo)) + combo
yield combo
This is a Python generator; making it a generator allows it to use up less RAM. There is a little work to be done after turning the number into a list of words; this is because these lists will need padding so that they are at the requested length. It would be used like this:
>>> list(combinations('01', 3))
[['0', '0', '0'], ['0', '0', '1'],
['0', '1', '0'], ['0', '1', '1'],
['1', '0', '0'], ['1', '0', '1'],
['1', '1', '0'], ['1', '1', '1']]
As you can see, you get back a list of lists. Each of these sub-lists contains a sequence of the original words; you might then do something like map(''.join, list(combinations('01', 3))) to retrieve the following result:
['000', '001', '010', '011', '100', '101', '110', '111']
You could then write this to disk; a better idea, however, would be to use the built-in optimizations that generators have and do something like this:
fileout = open('filename.txt', 'w')
fileout.writelines(
''.join(combo) for combo in combinations('01', 3))
fileout.close()
This will only use as much RAM as necessary (enough to store one combination). I hope this helps.
# Given two lists of strings, return a list of all ways to concatenate
# one from each.
def combos(xs, ys):
return [x + y for x in xs for y in ys]
digits = ['0', '1']
for c in combos(digits, combos(digits, digits)):
print c
#. 000
#. 001
#. 010
#. 011
#. 100
#. 101
#. 110
#. 111
It shouldn't be too hard in most languages. Does the following pseudo-code help?
for(int i=0; i < 2^digits; i++)
{
WriteLine(ToBinaryString(i));
}
A basic function to produce all the permutations of a list is given below. In this approach, permutations are created lazily by using generators.
def perms(seq):
if seq == []:
yield []
else:
res = []
for index,item in enumerate(seq):
rest = seq[:index] + seq[index+1:]
for restperm in perms(rest):
yield [item] + restperm
alist = [1,1,0]
for permuation in perms(alist):
print permuation

Categories