Filling an array with changing string value - python

I want to fill an array with word suffixes while making a dictionary with their indexes.
In a loop I do the following:
for i in range(len(s)):
suf = s[:j]
suff_dict.update({suf: i})
suff_arr[i][0] = suf
suff_arr[i][1] = 0
j -= 1
The dictionary is filled right, however, the array is filled only with the 1st letter.
[['H', 0], ['H', 0], ['H', 0], ['H', 0], ['H', 0], ['H', 0]]
{'HELLO': 1, 'HELL': 2, 'HEL': 3, 'HE': 4, 'H': 5}
Could you help me to find a problem?

I think maybe this is what you are looking for.
s='HELLO'
suff_arr=[]
suff_dict={}
for i in range(len(s)):
suf = s[i:]
suff_dict.update({suf: i})
suff_arr.append(suf)
print(suff_arr, suff_dict)
I do not really unterstand why you would have nested lists, with a zero, but if you want that you could do it like this:
s='HELLO'
suff_arr=[]
suff_dict={}
for i in range(len(s)):
suf = s[i:]
suff_dict.update({suf: i})
suff_arr.append([suf,0])
print(suff_arr, suff_dict)
Also you said you wanted the word suffixes not prefixes, so I changed that too. If you want the prefixes, simply replace s[i:] with s[:i+1]

Since the data in this question is unclear I can't exactly guess what you are trying to do. But from what I understand this might help u.
s = 'HELLO'
suff_dict = {}
j=len(s)
suff_arr = []
for i in range(len(s)):
suf = s[:j]
suff_dict.update({suf: i})
suff_arr.append([suf,0])
j -= 1

First off, as the previous answers have indicated, this is a case for building your list with "append()". Here is some explanation for the unexpected results you were seeing, it has to do with how Python stores and refers to objects in memory.
Copy and run the code below, it's my attempt to show why you were getting unexpected results in your list. The "id()" function in Python returns a unique identifier for an object, and I use it to show where list values are being stored in memory.
print('**** Values stored directly in list. ****')
arr = [0] * 3
print('All the items in the list refer to the same memory address.')
c = 0
for item in arr:
print(f'arr[{c}] id = ', id(item))
c += 1
print('\n')
for i in range(len(arr)):
arr[i] = i
print('As values are updated, new objects are created in memory:')
c = 0
for item in arr:
print(f'arr[{c}] id = ', id(item))
c += 1
print('And we see the results we expect:')
print(arr)
print('\n')
print('**** Values stored in sub list. ****')
arr = [[0]] * 3
print('All the items in the list refer to the same memory location.')
c = 0
for item in arr:
print(f'arr[{c}] id = ', id(item))
c += 1
print('\n')
for i in range(len(arr)):
arr[i][0] = i
print('The same memory address is repeatedly overwritten.')
c = 0
for item in arr:
print(f'arr[{c}] id = ', id(item))
c += 1
print('\n')
print('And we say "Wut??"')
print(arr)

Related

Find duplicates in a list of strings differing only in upper and lower case writing

I have a list of strings that contains 'literal duplicates' and 'pseudo-duplicates' which differ only in lower- and uppercase writing. I am looking for a function that treats all literal duplicates as one group, returns their indices, and finds all pseudo-duplicates for these elements, again returning their indices.
Here's an example list:
a = ['bar','bar','foo','Bar','Foo','Foo']
And this is the output I am looking for (a list of lists of lists):
dupe_list = [[[0,1],[3]],[[2],[4,5]]]
Explanation: 'bar' appears twice at the indexes 0 and 1 and there is one pseudo-duplicate 'Bar' at index 3. 'foo' appears once at index 2 and there are two pseudo-duplicates 'Foo' at indexes 4 and 5.
Here is one solution (you didn't clarify what the logic of list items will be and i considered that you want the items in lower format as they are met from left to right in the list, let me know if it must be different):
d={i:[[], []] for i in set(k.lower() for k in a)}
for i in range(len(a)):
if a[i] in d.keys():
d[a[i]][0].append(i)
else:
d[a[i].lower()][1].append(i)
result=list(d.values())
Output:
>>> print(result)
[[[0, 1], [3]], [[2], [4, 5]]]
Here's how I would achieve it. But you should consider using a dictionary and not a list of list of list. Dictionaries are excellent data structures for problems like this.
#default argument vars
a = ['bar','bar','foo','Bar','Foo','Foo']
#initalize a dictionary to count occurances
a_dict = {}
for i in a:
a_dict[i] = None
#loop through keys in dictionary, which is values from a_list
#loop through the items from list a
#if the item is exact match to key, add index to list of exacts
#if the item is similar match to key, add index to list of similars
#update the dictionary key's value
for k, v in a_dict.items():
index_exact = []
index_similar = []
for i in range(len(a)):
print(a[i])
print(a[i] == k)
if a[i] == str(k):
index_exact.append(i)
elif a[i].lower() == str(k):
index_similar.append(i)
a_dict[k] = [index_exact, index_similar]
#print out dictionary values to assure answer
print(a_dict.items())
#segregate values from dictionary to its own list.
dup_list = []
for v in a_dict.values():
dup_list.append(v)
print(dup_list)
Here is the solution. I have handled the situation where if there are only pseudo duplicates present or only literal duplicates present
a = ['bar', 'bar', 'foo', 'Bar', 'Foo', 'Foo', 'ka']
# Dictionaries to store the positions of words
literal_duplicates = dict()
pseudo_duplicates = dict()
for index, item in enumerate(a):
# Treates words as literal duplicates if word is in smaller case
if item.islower():
if item in literal_duplicates:
literal_duplicates[item].append(index)
else:
literal_duplicates[item] = [index]
# Handle if only literal_duplicates present
if item not in pseudo_duplicates:
pseudo_duplicates[item] = []
# Treates words as pseudo duplicates if word is in not in smaller case
else:
item_lower = item.lower()
if item_lower in pseudo_duplicates:
pseudo_duplicates[item_lower].append(index)
else:
pseudo_duplicates[item_lower] = [index]
# Handle if only pseudo_duplicates present
if item not in literal_duplicates:
literal_duplicates[item_lower] = []
# Form final list from the dictionaries
dupe_list = [[v, pseudo_duplicates[k]] for k, v in literal_duplicates.items()]
Here is the simple and easy to understand answer for you
a = ['bar','bar','foo','Bar','Foo','Foo']
dupe_list = []
ilist = []
ilist2 =[]
samecase = -1
dupecase = -1
for i in range(len(a)):
if a[i] != 'Null':
ilist = []
ilist2 = []
for j in range(i+1,len(a)):
samecase = -1
dupecase = -1
# print(a)
if i not in ilist:
ilist.append(i)
if a[i] == a[j]:
# print(a[i],a[j])
samecase = j
a[j] = 'Null'
elif a[i] == a[j].casefold():
# print(a[i],a[j])
dupecase = j
a[j] = 'Null'
# print(samecase)
# print(ilist,ilist2)
if samecase != -1:
ilist.append(samecase)
if dupecase != -1:
ilist2.append(dupecase)
dupe_list.append([ilist,ilist2])
a[i]='Null'
print(dupe_list)

Split a list and create partitions(list) depending upon the unique set of values

deck = [1,2,3,4,4,3,2,1]
Output: True
Explanation: Possible partition [1,1],[2,2],[3,3],[4,4].
Input: deck = [1,1,1,2,2,2,3,3]
Output: False
Explanation: No possible partition.
The solution i tried was very , very basic but i couldn't solve further than this. P.S:I am starting my coding experience.
v=[1,2,3,4,4,3,2,1]
t=list()
flag=0
for i in v:
t.append(v.count(i))
for i in range(len(t)):
for j in range(len(t)):
if(t[i]==t[j]):
flag=0
else:
flag=1
if(flag==1):
print("NO")
else:
q=len(list(set(v)))
n = q
lists = [[] for _ in range(n)]
Try this:
How it works - It goes through all the list and stores the occurrence of each value. Then It makes of a set of it. Returns true if length of set is 1 i.e every number appears exactly the same number of times.
EDIT - set has a property that its element dont repeat. So say if the value of dikt is {1: 3, 2:3, 3:3} then the value of dikt.values is [3,3,3]. Making a set out of it will be (3).
IF the value of dikt was {1:3, 2:3, 3:2} then the set would be (3, 2)
def foo(x):
dikt = {}
for i in x:
if i in dikt.keys():
dikt[i]+=1
else:
dikt[i] = 1
return len(set(dikt.values())) == 1
You can use Counter here.
from collections import Counter
def partition(lst):
count=Counter(lst)
if len(set(count.values()))>1:
return 'No partition'
else:
return [[i]*n for i,n in count.items()]
deck = [1,2,3,4,4,3,2,1]
partition(deck)
#[[1, 1], [2, 2], [3, 3], [4, 4]]
deck=[1,1,1,2,2,2,3,3]
partition(deck)
#'No partition found'
If you just want the output to be True or False try this.
def partition(lst):
return len(set(Counter(lst).values()))==1

Find and replace some elements in a list using python

I have to search all elements in a list and replace all occurrences of one element with another. What is the best way to do this?
For example, suppose my list has the following elements:
data = ['a34b3f8b22783cf748d8ec99b651ddf35204d40c',
'baa6cb4298d90db1c375c63ee28733eb144b7266',
'CommitTest.txt',
'=>',
'text/CommitTest.txt',
'0',
'README.md',
'=>',
'text/README.md',
'0']
and I need to replace all occurrences of character '=>' with the combined value from elements before and after the character '=>', so the output I need is:
data = ['a34b3f8b22783cf748d8ec99b651ddf35204d40c',
'baa6cb4298d90db1c375c63ee28733eb144b7266',
'CommitTest.txt=>text/CommitTest.txt',
'0',
'README.md=>text/README.md',
'0']
This is my code I wrote so far:
ind = data.index("=>")
item_to_replace = data[ind]
combine = data[ind-1]+data[ind]+data[ind+1]
replacement_value = combine
indices_to_replace = [i for i,x in enumerate(data) if x==item_to_replace]
for i in indices_to_replace:
data[i] = replacement_value
data
However, the unwanted output is like this :
data = ['a34b3f8b22783cf748d8ec99b651ddf35204d40c',
'baa6cb4298d90db1c375c63ee28733eb144b7266',
'CommitTest.txt',
'CommitTest.txt=>text/CommitTest.txt',
'text/CommitTest.txt',
'0',
'README.md',
'CommitTest.txt=>text/CommitTest.txt',
'text/README.md',
'0']
Is there a better way?
Your general algorithm is correct.
However, data.index("->") will only find the index of the first occurance of "->".
You need to find all occurrences of "=>" store it in a list, combine the elements and replace for each of the occurances.
To find the index of all occurance of "=>", you can use:
indices = [i for i, x in enumerate(data) if x == "=>"]
As #alpha_989 suggested first find the index of => element and replace for each occurances, hope this may help
>>> indices = [i for i, x in enumerate(data) if x == "=>"]
>>> for i in indices: #this will add one index upper and one index lower of elem "=>" with elem
data[i-1] = data[i-1]+ data[i] + data[i+1]
>>> for elem in data:
if elem == "=>":
del data[data.index("=>")+1]
del data[data.index("=>")]
>>> data
['a34b3f8b22783cf748d8ec99b651ddf35204d40c', 'baa6cb4298d90db1c375c63ee28733eb144b7266', 'CommitTest.txt=>text/CommitTest.txt', '0', 'README.md=>text/README.md', '0']
It was correctly pointed out to you that data.index will only return the index of the first occurence of an element. Furthermore, you code does not remove the entries after and before the "=>".
For a solution that mutates your list, you could use del, but I recommend using this neat slicing syntax that Python offers.
indices = [i for i, val in enumerate(data) if val == '=>']
for i in reversed(indices):
data[i-1: i+2] = [data[i-1] + data[i] + data[i+1]]
I also suggest you attempt an implementation that generates a new list in a single pass. Mutating a list can be a bad practice and has no real advantage over creating a new list like so.
new_data = []
i = 0
while i < len(data):
if i + 1 < len(data) and data[i + 1] == "=>":
new_data.append(data[i] + data[i+1] + data[i+2])
i += 3
else:
new_data.append(data[i])
i += 1
Below is my little experiment, I added a function to call. You can check for it:
data = ['a34b3f8b22783cf748d8ec99b651ddf35204d40c',
'baa6cb4298d90db1c375c63ee28733eb144b7266',
'CommitTest.txt',
'=>',
'text/CommitTest.txt',
'0',
'README.md',
'=>',
'text/README.md',
'0']
def convert_list():
ind = [i for i, x in enumerate(data) if x == "=>"]
if ind == 0 or ind == len(data) - 1:
print("Invalid element location")
return
new_data = []
index_start = 0
while index_start < len(data):
for ind_index in ind:
if index_start == ind_index -1:
index_start += 3
new_data.append(data[ind_index - 1] + data[ind_index] +data[ind_index + 1])
new_data.append(data[index_start])
index_start += 1
return new_data
print(convert_list())
The indexs that need to be deleted are saved first, then deleted.
delete_index=[]
for i,d in enumerate(data):
if(d=="=>"):
data[i]=data[i-1]+data[i]+data[i+1]
delete_index.append(i-1)
delete_index.append(i+1)
new_data=[]
for i,d in enumerate(data):
if i not in delete_index:
new_data.append(d)
print(new_data)

I want to write a function that takes a list and returns a count of total number of duplicate elements in the list

I have tried this, for some unknown reason when it prints h, it prints None, so i thought if it counts the number of None printed then divided by 2 it will give the number of duplicates, but i cant use function count here
a= [1,4,"hii",2,4,"hello","hii"]
def duplicate(L):
li=[]
lii=[]
h=""
for i in L:
y= L.count(i)
if y>1:
h=y
print h
print h.count(None)
duplicate(a)
Use the Counter container:
from collections import Counter
c = Counter(['a', 'b', 'a'])
c is now a dictionary with the data: Counter({'a': 2, 'b': 1})
If you want to get a list with all duplicated elements (with no repetition), you can do as follows:
duplicates = filter(lambda k: c[k] > 1, c.iterkeys())
If you want to only count the duplicates, you can then just set
duplicates_len = len(duplicates)
You can use a set to get the count of unique elements, and then compare the sizes - something like that:
def duplicates(l):
uniques = set(l)
return len(l) - len(uniques)
i found an answer which is
a= [1,4,"hii",2,4,"hello",7,"hii"]
def duplicate(L):
li=[]
for i in L:
y= L.count(i)
if y>1:
li.append(i)
print len(li)/2
duplicate(a)
the answer by egualo is much better, but here is another way using a dictionary.
def find_duplicates(arr):
duplicates = {}
duplicate_elements = []
for element in arr:
if element not in duplicates:
duplicates[element] = False
else:
if duplicates[element] == False:
duplicate_elements.append(element)
duplicates[element] = True
return duplicate_elements
It's pretty simple and doesn't go through the lists twice which is kind of nice.
>> test = [1,2,3,1,1,2,2,4]
>> find_duplicates(test)
[1, 2]

Dictionary deletion of values going out of index

I have a dictionary
k = {'a':[7,2,3],'b':[7,2,7], 'c': [8,9,10]}
where is each val is a list. I want to delete the ith term(depending on condition) in a val without going out of range. this is code for it
for i in range(len(k['a'])):
if k['a'][i] == k['b'][i]:
pass
else:
for key in k:
del [k[key][i]]
This would work return a dictionary equivalent to this
{'a':[7,2],'b':[7,2], 'c': [8,9]}
However if the dictionary was this
k = {'a':[6,2,3],'b':[7,2,7], 'c': [8,9,10]}
I would get this Error
list index out of range
How I delete key vals so I don't get this error?
The issue is that when you delete one item from each array, the size of these arrays decreases by one. Thus, the main loop becomes one iteration too long.
An illustration of the problem:
>>> a = [1, 2, 3]
>>> i = 2
>>> a[i]
3
>>> len(a)
3
>>> del [a[1]]
>>> a
[1, 3]
>>> len(a)
2
>>> a[i] # used to work
IndexError: list index out of range
In order for the index and the loop duration to work out you need to do something like this:
i = 0
while i < len(k['a']):
if k['a'][i] == k['b'][i]:
i += 1
else:
for key in k:
del [k[key][i]]

Categories