I have tried many things but still stuck. This is mostly because I'm failing to understand how python loops through an array or what options I have to loop through it.
I want to build an array: 4 columns, 18 rows.
I need the first column of each row to be a persons name in the person_list. Every 3 rows of my array I would then increment to the next person.
It would seem that my loop is not looping through the array the way I intended. It seems that it sets all values in the first column equal to the person_list value.
person_list = ["person1", "person2","person3","person4","person5","person6"]
my_array = [[0]*4]*len(person_list)*3
i=0
j=1
for row in my_array:
while j <= 3:
row[0] = person_list[i]
j+=1
j=1
i+=1
So the goal would be the resulting array
[
["person1", 0, 0, 0],
["person1", 0, 0, 0],
["person1", 0, 0, 0],
["person2", 0, 0, 0],
["person2", 0, 0, 0],
["person2", 0, 0, 0],
["person3", 0, 0, 0],
["person3", 0, 0, 0],
...
]
The problem seems to stem from the way my_array was initialized. Each row is 'nested' with the other rows, by that I mean if you try to modify my_array[0], you will end up modify all the remaining rows. Here is an example to illustrate that:
my_array[0].insert(0, 'hello_world')
# this prints:
# [['hello_world', 0, 0, 0],
['hello_world', 0, 0, 0],
....
['hello_world', 0, 0, 0]]
To get around, this you can use numpy to initialize your array of zeros or do something like this:
my_array = [[0, 0, 0, 0] for i in range(18)]
To make the code slight more concise and print the expected output, you can then do the following:
for i in range(len(person_list)):
# person1 : idx 0, 1, 2
# person2 : idx 3, 4, 5
# ...
end_idx = (i + 1) * 3
start_idx = end_idx - 3
for sub_arr in arr[start_idx:end_idx]:
sub_arr.insert(0, person_list[i])
Hope this helped!
You could use the modulo % to increment at certain intervals. For example, row%3==0 will return True at multiples of 3. FYI in your above code you were not resetting the row variable every interval of 3.
person_list = ["person1", "person2","person3","person4","person5","person6"]
my_array = [[0]*4]*len(person_list)*3
j=0
i=0
for row in my_array:
if j%3==0:
row[0] = person_list[i]
i+=1
j+=1 # increment the row here
I think everything is good in your code, you are just multiplying it by 3 :
person_list = ["person1", "person2","person3","person4","person5","person6"]
my_array = [[0]*4]*len(person_list)
i=0
j=1
for row in my_array:
while j <= 3:
row[0] = person_list[i]
j+=1
j=1
i+=1
I think its this like which needs to change from my_array = [[0]*4]*len(person_list)*3 to my_array = [[0]*4]*len(person_list)
So I think NeuralX was helpful in pointing out the way I create the array is not going to work for what I intend to do to it. He is absolutely correct when I run a change it will update every entry in the final array.
In more searching with working with nested lists, I have found how I should create the array so that I can update nested lists individually by looping through it. The final results are going to be below.
person_list = ["person1", "person2","person3","person4","person5","person6"]
# The way I create the array appears the be the main root cause here. I need to create it like this
my_array = [[0 for x in range(4)] for y in range(sum(person_assessments))]
i=0
j=0
for person in person_list:
for assessment in range(1, 4):
my_array[i][0] = person
# print(person, ", ", assessment)
# print(i,", ", j,", ", person)
i+=1
j += 1
print(my_array)
Related
I have names of people that are friends and I am looking for triangles of friends, if there are any.
Example (names next to each other classify as friends, in the first row the first number represents the number of people and the second number represents number of friendships):
6 7
mirko slavko
slavko janko
janko mirko
slavko luka
luka mirjana
mirjana ivana
ivana luka
In this example, janko - mirko - slavko is one and mirjana - luka - ivana is an another triangle.
I wrote a code which generates a 2d list which represents this graph.
L = [input().split() for i in range (n)]
H=[]
for i in range(n):
for j in range(2):
if L[i][j] not in H:
H.append(L[i][j])
H.sort()
for number, name in enumerate(H):
for i in range (n):
for j in range(2):
L[i][j]=L[i][j].replace(name, str(number))
matrix = [[0 for i in range(m)] for j in range(m)]
for i, j in L:
matrix[int(i)][int(j)]=matrix[int(j)][int(i)]=1
the graph looks like this (names are sorted alphabeticly, each row and column represent a name, 1 represents that a friendship exists, 0 represent that these two people aren't friends):
[0, 0, 1, 1, 0, 0]
[0, 0, 0, 0, 1, 1]
[1, 0, 0, 1, 0, 1]
[1, 0, 1, 0, 0, 0]
[0, 1, 0, 0, 0, 1]
[0, 1, 1, 0, 1, 0]
My question is how to find a triangle with code??
Most forms of the clique problem are difficult, the most general solutions are NP complete. Therefore O(N**3) is probably the best you can do assuming the input representation is efficient, and since you already made the 2d matrix you are most of the way there.
friends = [
[0,1,1,0],
[1,0,1,1],
[1,1,0,0],
[0,1,0,0]]
n = 4
for i in range(n):
for j in range(i+1, n):
if not friends[i][j]:
continue
for k in range(j+1, n):
if friends[i][k] and friends[j][k]:
print('friends!')
print(i,j,k)
The dead simple method would be
Create a dictionary whose key is the people's names, and the value is the set of friends of that person. Make sure that if A is in the set of friends of B, that B is also in the set of friends of A.
For each pair of people A and B, see if friends[A].intersect(friends[B]) is empty.
All I am trying to do is populate an array with numbers in order. So, array[0][0] = 0, array[0][1]=1, etc. Why is this not working? I cannot figure it out.
def populateArray(ar):
count = 0
i=0
j=0
while (i<len(ar)):
while (j<len(ar[i])):
ar[i][j] = count
count = count + 1
j=j+1
j=0
i=i+1
return ar
numColumns = input('how many columns?')
numRows = input('how many rows?')
arr = [[0]*int(numColumns)]*int(numRows)
arr=populateArray(arr)
print(arr)
when you initiate your arr variable, you are multiplying a list of lists with a number, this results in a "mess" because what you actually do it is to multiply only the reference of the first list (from your list of lists), so actually you have in your arr only one list and a bunch of reference to that list, to fix this you can do:
arr = [[0] * int(numColumns) for _ in range(int(numRows))]
or:
arr = [[0 for _ in range(int(numColumns))] for _ in range(int(numRows))]
after changing this in your code, for numRows = 3 and numColumns = 4 you get:
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
When you use this syntax to create multi dimensional array
arr = [[0]*int(numColumns)]*int(numRows)
the reference of same element is created many times , so if you assign a value to one of them then you are basically changing all the elements because they all reference to the same data.
for ex :
arr = [[0]*int(numColumns)]*int(numRows)
arr[0][1]=2
print(arr)
output
[[0, 2], [0, 2], [0, 2], [0, 2]]
I only changed one element and this is the result .
you should use :
arr = [[0 for i in range(int(numColumns))] for j in range(int(numRows))]
arr[0][1]=2
print(arr)
output :
[[0, 2], [0, 0], [0, 0], [0, 0]]
You can do this:
numColumns = input('how many columns?')
numRows = input('how many rows?')
arr = [[i+j for i in range(int(numRows))] for j in range(int(numColumns))]
arr=populateArray(arr)
print(arr)
The problem with your code is that you append same array to the main array multiple times, like this [l, l, l] and l is a list.
So when ever you change an elemenet of l it will change all of ls in your list.
So, your code works fine but each time you change another list, all of previous list will be effected.
You can also make use of numpy for creating the structure, followed by using numpy.tolist() for converting it to a python list
import numpy as np
numColumns = int(input('how many columns?'))
numRows = int(input('how many rows?') )
arr = np.arange(numRows*numColumns).reshape(numRows, numColumns).tolist()
print(arr)
I am working on moving all zeroes to end of list. .. is this approach bad and computationally expensive?
a = [1, 2, 0, 0, 0, 3, 6]
temp = []
zeros = []
for i in range(len(a)):
if a[i] !=0:
temp.append(a[i])
else:
zeros.append(a[i])
print(temp+zeros)
My Program works but not sure if this is a good approach?
A sorted solution that avoids changing the order of the other elements is:
from operator import not_
sorted(a, key=not_)
or without an import:
sorted(a, key=lambda x: not x) # Or x == 0 for specific numeric test
By making the key a simple boolean, sorted splits it into things that are truthy followed by things that are falsy, and since it's a stable sort, the order of things within each category is the same as the original input.
This looks like a list. Could you just use sort?
a = [1, 2, 0, 0, 0, 3, 6]
a.sort(reverse=True)
a
[6, 3, 2, 1, 0, 0, 0]
To move all the zeroes to the end of the list while preserving the order of all the elements in one traversal, we can keep the count of all the non-zero elements from the beginning and swap it with the next element when a non-zero element is encountered after zeroes.
This can be explained as:
arr = [18, 0, 4, 0, 0, 6]
count = 0
for i in range(len(arr):
if arr[i] != 0:
arr[i], arr[count] = arr[count], arr[i]
count += 1
How the loop works:
when i = 0, arr[i] will be 18, so according to the code it will swap with itself, which doesn't make a difference, and count will be incremented by one. When i=1, it will have no affect as till now the list we have traversed is what we want(zero in the end). When i=4, arr[i]= 4 and arr[count(1)]= 0, so we swap them leaving the list as[18, 4, 0, 0, 0, 6] and count becomes 2 signifying two non-zero elements in the beginning. And then the loop continues.
You can try my solution if you like
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
for num in nums:
if num == 0:
nums.remove(num)
nums.append(num)
I have tried this code in leetcode & my submission got accepted using above code.
Nothing wrong with your approach, really depends on how you want to store the resulting values. Here is a way to do it using list.extend() and list.count() that preserves order of the non-zero elements and results in a single list.
a = [1, 2, 0, 0, 0, 3, 6]
result = [n for n in a if n != 0]
result.extend([0] * a.count(0))
print(result)
# [1, 2, 3, 6, 0, 0, 0]
You can try this
a = [1, 2, 0, 0, 0, 3, 6]
x=[i for i in a if i!=0]
y=[i for i in a if i==0]
x.extend(y)
print(x)
There's nothing wrong with your solution, and you should always pick a solution you understand over a 'clever' one you don't if you have to look after it.
Here's an alternative which never makes a new list and only passes through the list once. It will also preserve the order of the items. If that's not necessary the reverse sort solution is miles better.
def zeros_to_the_back(values):
zeros = 0
for value in values:
if value == 0:
zeros += 1
else:
yield value
yield from (0 for _ in range(zeros))
print(list(
zeros_to_the_back([1, 2, 0, 0, 0, 3, 6])
))
# [1, 2, 3, 6, 0, 0, 0]
This works using a generator which spits out answers one at a time. If we spot a good value we return it immediately, otherwise we just count the zeros and then return a bunch of them at the end.
yield from is Python 3 specific, so if you are using 2, just can replace this with a loop yielding zero over and over.
Numpy solution that preserves the order
import numpy as np
a = np.asarray([1, 2, 0, 0, 0, 3, 6])
# mask is a boolean array that is True where a is equal to 0
mask = (a == 0)
# Take the subset of the array that are zeros
zeros = a[mask]
# Take the subset of the array that are NOT zeros
temp = a[~mask]
# Join the arrays
joint_array = np.concatenate([temp, zeros])
I tried using sorted, which is similar to sort().
a = [1, 2, 0, 0, 0, 3, 6]
sorted(a,reverse=True)
ans:
[6, 3, 2, 1, 0, 0, 0]
from typing import List
def move(A:List[int]):
j=0 # track of nonzero elements
k=-1 # track of zeroes
size=len(A)
for i in range(size):
if A[i]!=0:
A[j]=A[i]
j+=1
elif A[i]==0:
A[k]=0
k-=1
since we have to keep the relative order. when you see nonzero element, place that nonzero into the index of jth.
first_nonzero=A[0] # j=0
second_nonzero=A[1] # j=1
third_nonzero=A[2] # j=2
With k we keep track of 0 elements. In python A[-1] refers to the last element of the array.
first_zero=A[-1] # k=-1
second_zero=A[-2] # k=-2
third_zero= A[-3] # k=-3
a = [4,6,0,6,0,7,0]
a = filter (lambda x : x!= 0, a) + [0]*a.count(0)
[4, 6, 6, 7, 0, 0, 0]
I would like to declare a dynamic 2 dimensional array in python. The number of columns will be fixed while the number of rows should be dynamic. am willing to use numpy as well. I am using python 3, so xrange does not work. Appreciate your help.
Here is how I would go about doing it
array2d = [list() for f in xrange(n)]
This creates N empty lists. From here you can index them like
array2d[x][y]
An Example in use
array2d = [list() for f in xrange(3)] # We have Three Empty Rows
# Array looks like this -- [[] [] []]
#lets add an item into the first row
array2d[0].append("A")
#Now it looks like this -- [["A"] [] []]
This should solve your problem. The function grow_rows will add any needed rows, using a fixed column count and initializing the entries with 0 (which you can change to anything you like):
def grow_rows(arr, row_cnt, col_cnt):
missing = row_cnt - len(arr)
if missing > 0:
arr.extend([[0] * col_cnt for i in range(missing)])
Here's an example using a fixed column count of 3. Before accessing an element in a row that has not yet been allocated, it calls grow_rows to create the needed rows:
col_cnt = 3
arr = []
print(arr)
grow_rows(arr, 2, col_cnt)
print(arr)
arr[1][2] = 123
print(arr)
Here is the output:
[]
[[0, 0, 0], [0, 0, 0]]
[[0, 0, 0], [0, 0, 123]]
Example for Python 3:
matrix = [list() for f in range(2)]
print(matrix)
Output:
[[], []]
Hey I am writing a function that takes a matrix input such as the one below and returns its inverse, where all the 1s are changed to 0s and all the 0s changed to 1s, while keeping the diagonal from top left to bottom right 0s.
An example input:
g1 = [[0, 1, 1, 0],
[1, 0, 0, 1],
[1, 0, 0, 1],
[0, 1, 1, 0]]
the function should output this:
g1 = [[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 1, 0, 0],
[1, 0, 0, 0]]
When I run the program, it throws a "list index out of range" error. I'm sure this is because the loops I have set up are trying to access values that do not exist, but how do I allow an input of unknown row and column size? I only know how to do this with a single list, but a list of lists? Here is the function, not including the test function that calls it:
def inverse_graph(graph):
# take in graph
# change all zeros to ones and ones to zeros
r, c = 0, 0 # row, column equal zero
while (graph[r][c] == 0 or graph[r][c] == 1): # while the current row has a value.
while (graph[r][c] == 0 or graph[r][c] == 1): # while the current column has a value
if (graph[r][c] == 0):
graph[r][c] = 1
elif (graph[r][c] == 1):
graph[r][c] = 0
c+=1
c=0
r+=1
c=0
r=0
# sets diagonal to zeros
while (g1[r][c] == 0 or g1[r][c] == 1):
g1[r][c]=0
c+=1
r+=1
return graph
This doesn't directly answer your question, but I want to point out that in Python you can often reduce and sometimes eliminate the need to use indexing by using a
for <element> in <container>:
statement. By use it along with the built-in enumerate() function, it's possible to get both the index and the corresponding element
for <index>,<element> in enumerate(<container>):
Applying them to your problem would allow something like this:
g1 = [[0, 1, 1, 0],
[1, 0, 0, 1],
[1, 0, 0, 1],
[0, 1, 1, 0]]
def inverse_graph(graph):
""" invert zeroes and ones in a square graph
but force diagonal elements to be zero
"""
for i,row in enumerate(graph):
for j,cell in enumerate(row):
row[j] = 0 if cell or i == j else 1
return graph
print(g1)
print(inverse_graph(g1))
Output:
[[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]]
[[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]]
Which is simpler and clearly works. Another point is that since you're applying the function to a mutable (changeable) container, a list-of-lists, there's really no need to return the container because it is being changed in-place. It's not wrong to do so because it can make using the function easier, but it's something you may not have realized.
You could shorten the function a little bit more and eliminate indexing altogether by using something called a list comprehension:
def inverse_graph(graph):
return [[0 if cell or i == j else 1
for j,cell in enumerate(row)]
for i,row in enumerate(graph)]
Because of the way they work, this version doesn't change the graph in-place, but instead creates and returns a new one.
while (graph[r][c] == 0 or graph[r][c] == 1): # while the current row has a value.
You have to make sure first, that both indices exist, prior to comparing its -possible- value to 0 or 1. This causes your exceptions. To invert your matrix you would want to do something like
for row in graph:
for idx, v in enumerate (row):
row [idx] = 0 if v else 1
The mistake is in your "while the current row has a value". This will be always true while you will iterate through the elements in the row, and when you'll reach past them, you'll get the exception.
Instead, use:
for r in range(len(graph):
for c in range(len(graph[0]):
# do something with graph[r][c]
It is fairly simple.
Basically you need to find the number of elements in the array
mylist = [1,2,3,4,5]
len(mylist) # returns 5
#this gives the number of elements.
rows=len(g1) # get the number of rows
columns=len(g1[0]) #get the number of columns
#Now iterate over the number of rows and columns
for r in range(0, rows):
for c in range (0,columns):
if (r==c):
g1[r][c]=0
else:
g1[r][c]=1-g1[r][c]
Hope that helps
Not an answer to your question but here is a 'easy' way to do it
return [[0 if i2==i else 1 if item == 0 else 0 for i2,item in enumerate(row)] for i,row in graph]