Related
This question already has answers here:
List of lists changes reflected across sublists unexpectedly
(17 answers)
Closed 12 months ago.
I have a list of lists in Python, such as
colours = [['1', '2', '3'], ['1', '2', '3'], ['1', '2', '3']]
All three lists are the same at the beginning. I want to remove the first 1 from the first list so that I have
colours = [['2', '3'], ['1', '2', '3'], ['1', '2', '3']]
but whatever I tried will remove the 1 from every list.
I tried doing colours[0].remove('1') but then the result is
colour = [['2', '3'], ['2', '3'], ['2', '3']]
How can I do it?
I have defined colours as:
list = ['1', '2', '3']
for i in range(3):
colours.append(list)
As per your code in the comment:
colours = []
list = ['1','2','3']
for i in range(3):
colours.append(list)
This is adding the same list 3 times. Therefore when you use:
colours[0].remove('1')
You are basically removing 1 from the original list. Therefore it is applied across colours as well. This is because all the lists in colours point to the same location in memory.
My suggestion is, first don't use the variable name list as it shadows the builtin list. Second to build the list you intended, use different lists every iteration:
colours = []
for i in range(3):
colours.append(['1','2','3'])
Or using a comprehension:
colours = [['1','2','3'] for i in range(3)]
You must be running it in a loop somewhere to remove the elements.
colours[0].remove('1') is good.
c = [['1', '2', '3'], ['1', '2', '3'], ['1', '2', '3']]
c[0].remove('1')
print (c)
[['2', '3'], ['1', '2', '3'], ['1', '2', '3']] --output
That sounds strange to me, I ran a quick test:
colours = [['1', '2', '3'], ['1', '2', '3'], ['1', '2', '3']]
colours[0].remove('1')
print(colours) #[['2', '3'], ['1', '2', '3'], ['1', '2', '3']]
Update your question with more information if the issue persists
this code generates a list of integers
dir_list = list(range(11))
dir_list
numpy could transfer each element to string type
import numpy as np
dir_list = np.array(dir_list, dtype=np.str)
dir_list
array(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10'],
dtype='<U2')
is there a way to finish the job within Python, without any other 3rd party packages?
You can simply map each integer to string using inbuilt map function and map returns iterator so you can convert it into list.
list(map(str, range(11))) should do.
output:
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
Of course, this way you can iterate over each element of range object and convert to str and store as list:
dir_list = [str(i) for i in range(11)]
>>> dir_list
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
Anyone knows how can I solve this issue?
I have the following code.
result=[]
for i in range(len(response_i['objcontent'][0]['rowvalues'])):
lat = response_i['objcontent'][0]['rowvalues'][i][0]
print(lat)
for i in lat:
result.append(i)
print (result)
Following is the output of print(lat):
92.213725
191.586143
228.981615
240.353291
and following is the output of print(result):
['9', '2', '.', '2', '1', '3', '7', '2', '5', '1', '9', '1', '.', '5', '8',
'6', '1', '4', '3', '2', '2', '8', '.', '9', '8', '1', '6', '1', '5', '2',
'4', '0', '.', '3', '5', '3', '2', '9', '1']
I expected to get the output in following format:
[92.213725, 191.586143, 228.981615, 240.353291]
Anyone knows how to fix this issue?
Thanks
So, your error is that instead of simply adding your latitute to the list, you are iterating over each character of the latitude, as a string, and adding that character to a list.
result=[]
for value in response_i['objcontent'][0]['rowvalues']:
lat = value[0]
print(lat)
result.append(float(lat))
print (result)
Besides that, using range(len(...))) is the way things have to be done in almost all modern languages, because they either don't implement a "for ...each" or do it in an incomplete or faulty way.
In Python, since the beginning it is a given that whenever one wants a for iteration he wants to get the items of a sequence, not its indices (for posterior retrieval of the indices). Some auxiliar built-ins come in to play to ensure you just interate the sequence: zip to mix one or more sequences, and enumerate to yield the indices as well if you need them.
I am looking a efficient way to find the 1st order neighbors of a given polygon. My data are in shapefile format.
My first idea was to calculate the x and y coordinates of the polygons' centroids in order to find the neighbor's centroids.
import pysal
from pysal.common import *
import pysal.weights
import numpy as np
from scipy import sparse,float32
import scipy.spatial
import os, gc, operator
def get_points_array_from_shapefile(inFile):
"""
Gets a data array of x and y coordinates from a given shape file
Parameters
----------
shapefile: string name of a shape file including suffix
Returns
-------
points: array (n,2) a data array of x and y coordinates
Notes
-----
If the given shape file includes polygons,
this function returns x and y coordinates of the polygons' centroids
Examples
--------
Point shapefile
>>> from pysal.weights.util import get_points_array_from_shapefile
>>> xy = get_points_array_from_shapefile('../examples/juvenile.shp')
>>> xy[:3]
array([[ 94., 93.],
[ 80., 95.],
[ 79., 90.]])
Polygon shapefile
>>> xy = get_points_array_from_shapefile('../examples/columbus.shp')
>>> xy[:3]
array([[ 8.82721847, 14.36907602],
[ 8.33265837, 14.03162401],
[ 9.01226541, 13.81971908]])
(source: https://code.google.com/p/pysal/source/browse/trunk/pysal/weights/util.py?r=1013)
"""
f = pysal.open(inFile)
shapes = f.read()
if f.type.__name__ == 'Polygon':
data = np.array([shape.centroid for shape in shapes])
elif f.type.__name__ == 'Point':
data = np.array([shape for shape in shapes])
f.close()
return data
inFile = "../examples/myshapefile.shp"
my_centr = get_points_array_from_shapefile(inFile)
This approach could be valid for a regular grid but in my case, I need to find a "more general" solution. The figure shows the problem. Consider the yellow polygon has the referee. The neighbor's polygons are the gray polygons. Using the centroids-neighbors approach, the clear blue polygon is considered a neighbor but it doesn't have a side in common with the yellow polygon.
A recent solution modified from Efficiently finding the 1st order neighbors of 200k polygons can be the following:
from collections import defaultdict
inFile = 'C:\\MultiShapefile.shp'
shp = osgeo.ogr.Open(inFile)
layer = shp.GetLayer()
BlockGroupVertexDictionary = dict()
for index in xrange(layer.GetFeatureCount()):
feature = layer.GetFeature(index)
FID = str(feature.GetFID())
geometry = feature.GetGeometryRef()
pts = geometry.GetGeometryRef(0)
# delete last points because is the first (see shapefile polygon topology)
for p in xrange(pts.GetPointCount()-1):
PointText = str(pts.GetX(p))+str(pts.GetY(p))
# If coordinate is already in dictionary, append this BG's ID
if PointText in BlockGroupVertexDictionary:
BlockGroupVertexDictionary[PointText].append(FID)
# If coordinate is not already in dictionary, create new list with this BG's ID
else:
BlockGroupVertexDictionary[PointText] = [FID]
With this solution, I have a dictionary with vertex coordinates as the keys and a list of block group IDs that have a vertex at that coordinate as the value.
>>> BlockGroupVertexDictionary
{'558324.3057036361423.57178': ['18'],
'558327.4401686361422.40755': ['18', '19'],
'558347.5890836361887.12271': ['1'],
'558362.8645026361662.38757': ['17', '18'],
'558378.7836876361760.98381': ['14', '17'],
'558389.9225016361829.97259': ['14'],
'558390.1235856361830.41498': ['1', '14'],
'558390.1870856361652.96599': ['17', '18', '19'],
'558391.32786361398.67786': ['19', '20'],
'558400.5058556361853.25597': ['1'],
'558417.6037156361748.57558': ['14', '15', '17', '19'],
'558425.0594576362017.45522': ['1', '3'],
'558438.2518686361813.61726': ['14', '15'],
'558453.8892486362065.9571': ['3', '5'],
'558453.9626046361375.4135': ['20', '21'],
'558464.7845966361733.49493': ['15', '16'],
'558474.6171066362100.82867': ['4', '5'],
'558476.3606496361467.63697': ['21'],
'558476.3607186361467.63708': ['26'],
'558483.1668826361727.61931': ['19', '20'],
'558485.4911846361797.12981': ['15', '16'],
'558520.6376956361649.94611': ['25', '26'],
'558525.9186066361981.57914': ['1', '3'],
'558527.5061096362189.80664': ['4'],
'558529.0036896361347.5411': ['21'],
'558529.0037236361347.54108': ['26'],
'558529.8873646362083.17935': ['4', '5'],
'558533.062376362006.9792': ['1', '3'],
'558535.4436256361710.90985': ['9', '16', '20'],
'558535.4437266361710.90991': ['25'],
'558548.7071816361705.956': ['9', '10'],
'558550.2603156361432.56769': ['26'],
'558550.2603226361432.56763': ['21'],
'558559.5872216361771.26884': ['9', '16'],
'558560.3288756362178.39003': ['4', '5'],
'558568.7811926361768.05997': ['1', '9', '10'],
'558572.749956362041.11051': ['3', '5'],
'558573.5437016362012.53546': ['1', '3'],
'558575.3048386362048.77518': ['2', '3'],
'558576.189546362172.87328': ['5'],
'558577.1149386361695.34587': ['7', '10'],
'558579.0999636362020.47297': ['1', '3'],
'558581.6312396362025.36096': ['0', '1'],
'558586.7728956362035.28967': ['0', '3'],
'558589.8015336362043.7987': ['2', '3'],
'558601.3250076361686.30355': ['7'],
'558601.3250736361686.30353': ['25'],
'558613.7793476362164.19871': ['2', '5'],
'558616.4062876361634.7097': ['7'],
'558616.4063116361634.70972': ['25'],
'558618.129066361634.29952': ['7', '11', '22'],
'558618.1290896361634.2995': ['25'],
'558626.9644156361875.47515': ['10', '11'],
'558631.2229836362160.17325': ['2'],
'558632.0261236361600.77448': ['25', '26'],
'558639.495586361898.60961': ['11', '13'],
'558650.4935686361918.91358': ['12', '13'],
'558659.2473416361624.50945': ['8', '11', '22', '24'],
'558664.5218136361857.94836': ['7', '10'],
'558666.4126376361622.80343': ['8', '24'],
'558675.1439056361912.52276': ['12', '13'],
'558686.3385396361985.08892': ['0', '1'],
..................
.................
'558739.4377836361931.57279': ['11', '13'],
'558746.8758486361973.84475': ['11', '13'],
'558751.3440576361902.20399': ['6', '11'],
'558768.8067026361258.4715': ['26'],
'558779.9170276361961.16408': ['6', '11'],
'558785.7399596361571.47416': ['22', '24'],
'558791.5596546361882.09619': ['8', '11'],
'558800.2351726361877.75843': ['6', '8'],
'558802.7700816361332.39227': ['26'],
'558802.770176361332.39218': ['22'],
'558804.7899976361336.78827': ['22'],
'558812.9707376361565.14513': ['23', '24'],
'558833.2667696361940.68932': ['6', '24'],
'558921.2068976361539.98868': ['22', '23'],
'558978.3570116361885.00604': ['23', '24'],
'559022.80716361982.3729': ['23'],
'559096.8905816361239.42141': ['22'],
'559130.7573166361935.80614': ['23'],
'559160.3907086361434.15513': ['22']}
Just incase this is still an open question for the OP or someone else stumbles here.
import pysal as ps
w = ps.queen_from_shapefile('shapefile.shp')
http://pysal.readthedocs.io/en/latest/users/tutorials/weights.html#pysal-spatial-weight-types
I am not familiar with the specific data formats being used, but regardless, think the following idea would work.
In Python you can make sets out of tuples of numbers, i.e. (x,y) and (x1,y1,x2,y2), so it should be possible to make a set representing all the points or edges in a given polygon. Afterwards you would be able use very fast set intersection operations to find all 1st order neighbors.
You might be able to speed the process up using some sort of trivial rejection test to avoid further processing of polygons which could not possibly be a neighbor -- perhaps using your polygons' centroids idea.
Does this explanation make sense?
This is quite complicated but i would like to be able to refresh a larger list once at item has been taken out of a mini list within the bigger list.
listA = ['1','2','3','4','5','6','6','8','9','5','3','7']
i used the code below to split it into lists of threes
split = [listA[i:(i+3)] for i in range(0, len(listA) - 1, 3)]
print(split)
# [['1','2','3'],['4','5','6'],['6','8','9'],['5','3','7']]
split = [['1','2','3'],['4','5','6'],['6','8','9'],['5','3','7']]
if i deleted #3 from the first list, split will now be
del split[0][-1]
split = [['1','2'],['4','5','6'],['6','8','9'],['5','3','7']]
after #3 has been deleted, i would like to be able to refresh the list so that it looks like;
split = [['1','2','4'],['5','6','6'],['8','9','5'],['3','7']]
thanks in advance
Not sure how big this list is getting, but you would need to flatten it and recalculate it:
>>> listA = ['1','2','3','4','5','6','6','8','9','5','3','7']
>>> split = [listA[i:(i+3)] for i in range(0, len(listA) - 1, 3)]
>>> split
[['1', '2', '3'], ['4', '5', '6'], ['6', '8', '9'], ['5', '3', '7']]
>>> del split[0][-1]
>>> split
[['1', '2'], ['4', '5', '6'], ['6', '8', '9'], ['5', '3', '7']]
>>> listA = sum(split, []) # <- flatten split list back to 1 level
>>> listA
['1', '2', '4', '5', '6', '6', '8', '9', '5', '3', '7']
>>> split = [listA[i:(i+3)] for i in range(0, len(listA) - 1, 3)]
>>> split
[['1', '2', '4'], ['5', '6', '6'], ['8', '9', '5'], ['3', '7']]
Just recreate the single list from your nested lists, then re-split.
You can join the lists, assuming they are only one level deep, with something like:
rejoined = [element for sublist in split for element in sublist]
There are no doubt fancier ways, or single-liners that use itertools or some other library, but don't overthink it. If you're only talking about a few hundred or even a few thousand items this solution is quite good enough.
I need this for turning of cards in the deck in a solitaire game.
You can deal your cards using itertools.groupby() with a good key function:
def group_key(x, n=3, flag=[0], counter=itertools.count(0)):
if next(counter) % n == 0:
flag[0] = flag[0] ^ 1
return flag[0]
^ is a bitwise operator, basically it change the value of the flag from 0 to 1 and viceversa. The flag value is an element of a list because we're doing some kind of memoization.
Example:
>>> deck = ['1', '2', '3', '4', '5', '6', '6', '8', '9', '5', '3', '7']
>>> for k,g in itertools.groupby(deck, key=group_key):
... print(list(g))
['1', '2', '3']
['4', '5', '6']
['6', '8', '9']
['5', '3', '7']
Now let's say you've used card '9' and '8', so your new deck looks like:
>>> deck = ['1', '2', '3', '4', '5', '6', '6', '5', '3', '7']
>>> for k,g in itertools.groupby(deck, key=group_key):
... print(list(g))
['1', '2', '3']
['4', '5', '6']
['6', '5', '3']
['7']
Build an object that contains a list and tracks when the list is altered (probably by controlling write to it), then have the object do it's own split every time the data is altered and save the split list to a member of the object.