I have nested lists (ie. [[list1],[list2]] and I want to make a change to only the first list.
My function is given as below:
function_name(data, list_number, change)
should return a change to only the list_number provided in the data
So my overall question is, how do I restrict this change to only the list_number given? If this is unclear please feel free to ask and clarify.
Ex:
Where the 'change' is already known which index it is going to replace, in this case it's going to replace the 2nd index of the first list (ie. 2)
data = [[1,2,3],[4,5,6]]
function_name(data, 1, 6)
data = [[1,6,3],[4,5,6]]
I have no idea where to even begin as the index is 'unknown' (ie. given by the user when the function is called)
List items are referenced via their index and nested lists can work the same way.
If your list were:
list = [['nest1_1', 'nest1_2']['nest2_1', 'nest2_2']]
You could change it in the following ways:
list[0] = ['nesta_1', 'nesta_2']
list[1][0] = 'second_1'
This would make your list now be:
[['nesta_1', 'nesta_2']['second_1', 'nest2_2']]
Try this code:
data = [[1,2,3],[4,5,6]]
def element_change(data, index_list, element_to_change, change):
a =''.join([ str(i) for i in data[index_list]])
data[index_list][a.find(str(element_to_change))] = change
return data
print(element_change(data, 0, 2, 6))
Input:
[[1, 2, 3], [4, 5, 6]]
Output:
[[1, 6, 3], [4, 5, 6]]
Simply what it does is casting list to string and merging them in order to be able to use find() method to find the index.
Related
I want to create a funciton getCombinations that given a list of positive integers and a maximum amount, appends all the possible combinations of the given integers that sum to the given amount to a list outside of the function.
For example:
combinations=[]
getCombinations([5,2,1], 10)
print(combinations)
should return:
[[5, 5], [5, 2, 2, 1], [5, 2, 1, 1, 1], [5, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2], ... , [1, 1, 1, 1, 1, 1, 1, 1, 1, 1,]
I tried to use a recursive function that loops over the given integers, and appends them to the list current_combinations.
If the sum of that list equals the given amount, it should append the current_combination.
If the sum is smaller it goes one level deeper and appends new numbers from the list.
combinations = []
def getCombinations(num_types, max_amount, current_combi=None):
if current_combi is None:
current_combi = []
for num in num_types:
current_combi.append(num)
if sum(current_combi) == max_amount:
combinations.append(current_combi)
elif sum(current_combi) < max_amount:
getCombinations(num_types, max_amount, current_combi)
current_combi = current_combi[:-1]
getCombinations([5, 2, 1], 10)
print(combinations)
But this only outputs a fraction of the anticipated result:
[[5, 5], [5, 2, 2, 1], [5, 2, 2, 1], [5, 2, 1, 2], [5, 2, 1, 1, 1], [5, 2, 2, 1], [5, 2, 2, 1], [5, 2, 1, 2], [5, 2, 1, 1, 1]]
Help would be much appreciated, thank you.
There are two main problems here.
First, there is the algorithmic problem, which is that in every recursive call, you start at the beginning of the list of possible values. That will inevitably lead to duplicated lists. You want the produced lists to be sorted in descending order (or, at least, in the same order as the original list), and you need to maintain that order by not recursing over values you have already finished with.
The second problem is subtler; it has to do with the way you handle the current_combi arrays, with emphasis on the plural. You shouldn't use multiple arrays; when you do, it's very easy to get confused. What you should do is use exactly one array, and only make a copy when you need to add it to the result.
You might need to pull out a pad of paper and a pencil and play computer to see what's going on, but I'll try to describe it. The key is that:
current_combi.append(num) modifies the contents of current_combi;
passing current_combi as a function argument does not create a new list;
current_combi = current_combi[:-1] does create a new list, and does not modify the old one.
So, you enter getCombinations and create a current_combi list. Then you push the first value onto the new list (so it's now [5] and recursively call getCombinations, passing the same list. Inside the recursive call, the first value is appended again onto the list (which is still the same list); that list is now [5, 5]. That's a valid result, so you add it to the accumulated results, and then you create a new current_combi. At this point, the original current_combi is still [5, 5] and the new one is [5]. Then the for loop continues (in the recursive call), but the rest of that loop no longer has access to the original current_combi. So we can fast forward to the end of the for loop, ignoring the recursive subcalls, and return to the top level.
When we return to the top level, current_combi is the list which was originally created, and that list had 5 appended to it twice, once in the top-level for loop and again when the first recursive call started. So it's still [5. 5], which is unexpected. A fundamental property of recursive backtracking is that the problem state variable be the same before and after each recursive call. But that property has been violated. So now at the end of the top-level for loop, an attempt is made to remove the 5 added at the beginning. But since that list is now [5, 5], removing the last element produces [5] instead of []. As a result, lists starting with 2 are never produced, and lists starting 5, 2 are produced twice.
OK, let's fix that. Instead of making copies of the list at uncontrolled points in the execution, we'll just use one list consistently, and make a copy when we add it to the accumulated results:
# This one still doesn't work. See below.
def getCombinations(num_types, max_amount, current_combi=None):
if current_combi is None:
current_combi = []
for num in num_types:
current_combi.append(num)
if sum(current_combi) == max_amount:
combinations.append(current_combi[:]) # Add a copy to results
elif sum(current_combi) < max_amount:
getCombinations(num_types, max_amount, current_combi)
current_combi.pop() # Restore current_combi
But that doesn't actually fix the first problem noted above: that the recursion should not reuse values which have already been used. Instead of looping over the values in num_types, we need to loop over its suffixes:
def getCombinations(num_types, max_amount, current_combi=None):
if current_combi is None:
current_combi = []
values = num_types[:] # Avoid modifying the caller's list
while values:
# values.pop(0) removes the first element in values and returns it
current_combi.append(values.pop(0))
if sum(current_combi) == max_amount:
combinations.append(current_combi[:]) # Add a copy to results
elif sum(current_combi) < max_amount:
getCombinations(values, max_amount, current_combi)
# Restore current_combi
current_combi.pop()
In the above, I was trying to roughly follow the logic of your original. However, the handling of values could be made more efficient by passing the starting index in the list instead of modifying the list. Also, there is no need to rescan the candidate combination in order to add up its value, since we can just add the value we just added (or, as in the following code, subtract it from the target). Finally, since a lot of the arguments to the recursive call are always the same, they can be replaced by a closure:
def getCombinations(num_types, max_amount):
results = []
candidate = []
def helper(first_index, amount_left):
for index in range(first_index, len(num_types)):
value = num_types[index]
if amount_left == value:
results.append(candidate + [value])
elif amount_left > value:
candidate.append(value)
helper(index, amount_left - value)
candidate.pop()
helper(0, max_amount)
return results
That's still not the optimal implementation, but I hope it shows how to evolve this implementation.
I have a list that contains many elements, where each element represents an input file, that I want to dynamically subset using the values contained within another list. For example, I have some code that dynamically generates lists that I want to use to define the sub-samples such as
[0, 1, 2, 3]
and
[1, 2, 3, 4]
But I want to use the start and end elements of each of these lists to define an slice range to be applied to another list. In other words, I want the two above lists to be converted into slices that look like this
[0:3]
and [1:4]
But I don't know how to do this, and to be honest I'm not even sure the correct terminology to use to search for this. I have tried searching stack overflow for 'dynamically generate slices from lists' or even 'dynamically generate data slice' (an variants that I can think of along those lines) without any success.
Here are a few more details:
thislist = ['2019/12/26/fjjd', '2019/12/26/defg', '2020/01/09/qpfd', '2020/01/09/tosf', '2020/01/16/zpqr', '2020/01/15/zpqr', '2020/01/15/juwi']
where someIndexSlice is
[0:3]
and generated from a list that looks like this
[0,1,2,3]
thislist[someIndexSlice] = ['2019/12/26/fjjd', '2019/12/26/defg', '2020/01/09/qpfd', '2020/01/09/tosf']
So my questions are:
How can I accomplish this?
What sort of terminology should I use to describe what I am trying to accomplish?
Thanks
You can use the built-in slice function:
>>> lst = [0, 1, 2, 3]
>>> as_slice = slice(lst[0], lst[-1], lst[1] - lst[0])
>>> as_slice
slice(0, 3, 1) # which is same as [0:3]
And then to check if it works correctly:
>>> test = [1, 5, 3, 7, 8]
>>> test[as_slice]
[1, 5, 3]
>>> test[0:3]
[1, 5, 3]
NOTE:
This implementation assumed your lists are equidistant, and sorted.
Say I'm receiving a list of arbitrary numbers from input, like
[1,2,3,4,5,6,7,8,8,9,10]
My code doesn't know what numbers these are going to be before it receives the list, and I want to return the number that appears twice automatically. How do I go about doing so?
Thank you.
You could do:
input = [1,2,3,4,5,6,7,8,8,9,10]
list_of_duplicates = []
for i in input:
if i not in list_of_duplicates:
list_of_duplicates.append(i)
input.pop(i)
print(input)
Now input will have all the numbers that were in the list multiple times.
You can use Counter By defualt Method in python 2 and 3
from collections import Counter
lst=[1,2,3,4,5,6,7,8,8,9,10]
items=[k for k,v in Counter(lst).items() if v==2]
print(items)
Hope this helps.
input = [1,2,3,4,5,6,7,8,8,9,10]
unique = set(input)
twice = []
for item in unique:
if input.count(item) == 2:
twice.append(item)
I've created something monstrous that does it in one line because my brain likes to think when it's time for bed I guess?
This will return a list of all duplicate values given a list of integers.
dupes = list(set(map(lambda x: x if inputList.count(x) >= 2 else None, inputList))-set([None]))
How does it work? The map() function applies a function every value of a list, in your case our input list with possible duplicates is called "inputList". It then applies a lambda function that returns the value of the integer being iterated over IF the iterated value when applied to the inputList via the .count() method is greater than or equal to two, else if it doesn't count as a duplicate it will return None. With this lambda function being applied by the map function, we get a list back that contains a bunch of None's and the actual integers detected as duplicates via the lambda function. Given that this is a list, we the use set to de-duplicate it. We then minus the set of duplicates against a static set made from a list with one item of None, stripping None values from our set of the map returned list. Finally we take the set after subtraction and convert it to a list called "dupes" for nice and easy use.
Example usage...
inputList = [1, 2, 3, 4, 4, 4, 5, 6, 6, 7, 1001, 1002, 1002, 99999, 100000, 1000001, 1000001]
dupes = list(set(map(lambda x: x if inputList.count(x) >= 2 else None, inputList))-set([None]))
print(dupes)
[1000001, 1002, 4, 6]
I'll let someone else elaborate on potential scope concerns..... or other concerns......
This will create a list of the numbers that are duplicated.
x = [1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10]
s = {}
duplicates = []
for n in x:
try:
if s[n]:
duplicates.append(n)
s[n] = False
except KeyError:
s[n] = True
print(duplicates)
Assuming the list doesn't contain 0
I have a list of integers containing:
intlist = [19,4,2,4]
and i want to append the value from the intlist into a list of list such that:
noDuplist = [[19,0],[4,1],[2,2]]
where the first index represents the value from the intlist and the second index represents the index of the value in the intlist. 19 is at index 0, 4 is at index 1 and 2 is at index 2. Since there is another 4 i do not want to include that since i didn't want duplicate hence the last 4 is just going to be left out.
I tried something like:
noDuplist = []
for i in range(len(intlist)):
if intlist[i] not in noDuplist:
noDuplist.append([intlist[i],i])
but I'm still getting
[[19, 0], [4, 1], [2, 2], [4, 3]]
where the [4,3] shouldnt be there. Would appreciate some help on this
I assume you want to retain the indices from the original sequence.
Thus what you want is something that remembers at what index was the value
first seen in the original sequence.
The problem is in your condition since
if intlist[i] not in noDuplist:
# something
would check if 4 was present in [[19, 0], [4, 1], [2, 2]]] which it isn't.
A cleaner way of doing this could be using dictionaries or sets.:
intlist = [19,4,2,4]
seen_so_far, noDuplist = set(), []
for i, v in enumerate(intlist):
if v not in seen_so_far:
noDuplist.append([v, i])
seen_so_far.add(v)
print(noDuplist)
Which gives the output [[19, 0], [4, 1], [2, 2]]
The first thing I'd suggest is not bothering storing the index as well as the value. You'll know the index when extracting elements anyway.
The first approach that comes to my mind (not sure if it's optimal) involves using a dictionary in combination with your list. Whenever you try to insert a value, check if it exists in your dictionary. If it doesn't, add it to the dictionary and your list. If it does, don't add it.
This would result in O(N) complexity.
Edit:
I didn't read your description thoroughly enough. Since you need the index from the original array, simply enter both as a key/value pair into your dictionary instead.
I am relatively new to python and I am still trying to learn the basics of the language. I stumbled upon a question which asks you to rearrange the list by modifying the original. What you are supposed to do is move all the even index values to the front (in reverse order) followed by the odd index values.
Example:
l = [0, 1, 2, 3, 4, 5, 6]
l = [6, 4, 2, 0, 1, 3, 5]
My initial approach was to just use the following:
l = l[::-2] + l[1::2]
However, apparently this is considered 'creating a new list' rather than looping through the original list to modify it.
As such, I was hoping to get some ideas or hints as to how I should approach this particular question. I know that I can use a for loop or a while loop to cycle through the elements / index, but I don't know how to do a swap or anything else for that matter.
You can do it by assigning to a list slice instead of a variable:
l[:] = l[::2][::-1] + l[1::2]
Your expression for the reversed even elements was also wrong. Use l[::2] to get all the even numbers, then reverse that with [::-1].
This is effectively equivalent to:
templ = l[::2][::-1] + l[1::2]
for i in range(len(l)):
l[i] = templ[i]
The for loop modifies the original list in place.