Làm thế nào để truy cập các hàng liền kề với con trỏ?


8

Trong ảnh chụp màn hình đính kèm, các thuộc tính chứa hai trường quan tâm "a" và "b". Tôi muốn viết một kịch bản để truy cập vào các hàng liền kề để thực hiện một số tính toán. Để truy cập vào một hàng, tôi sẽ sử dụng UpdateCoder sau:

fc = r'C:\path\to\fc'

with arcpy.da.UpdateCursor(fc, ["a", "b"]) as cursor:
     for row in cursor:
          # Do something

Ví dụ: với OBRIID 4, tôi quan tâm đến việc tính tổng các giá trị hàng trong trường "a" liền kề với hàng OBRIID 4 (tức là 1 + 3) và thêm giá trị đó vào hàng OBRIID 4 trong trường "b". Làm cách nào tôi có thể truy cập các hàng liền kề bằng con trỏ để thực hiện các loại tính toán này?

nhập mô tả hình ảnh ở đây

Câu trả lời:


7

Nếu đây là tôi, tôi sẽ chuyển qua bảng một khi tạo một từ điển trong đó khóa là OBRIID và mục là giá trị trong trường "a". Sau đó, tôi sẽ bước qua bảng với một con trỏ cập nhật nhận OBRIID và từ đó tôi có thể nhận các giá trị liền kề từ từ điển, tổng hợp chúng và viết chúng trở lại trường "b".

Nhưng trong ảnh chụp màn hình của bạn, bạn có các trường hợp đặc biệt cho hàng 3 và 8 vì chúng chỉ có một hàng liền kề. Bạn có ý định gì cho những điều này?


+1 Đây là một giải pháp tốt vì nó có thể được sử dụng theo cách tôn trọng mô hình dữ liệu quan hệ. Trong mô hình này, chuỗi trong đó các hàng được xử lý là không xác định, do đó, bất kỳ quy trình nào dựa trên giả định rằng chúng sẽ được lặp lại theo cùng một thứ tự được hiển thị trong chế độ xem bảng nên được coi là không đáng tin cậy. Bằng cách sử dụng bất kỳ khóa nào - không chỉ OBJECTID- giải pháp này có thể xác định đáng tin cậy hàng xóm theo các giá trị của khóa đó. Tuy nhiên, từ điển thường không hỗ trợ tra cứu "tiếp theo" hoặc "trước đó". Bạn cần một cái gì đó giống như một Trie .
whuber

4

Trong khi lặp qua các hàng bạn cần theo dõi các giá trị trước đó. Đây là một cách để làm điều đó:

 previous_value = None
 cursor = arcpy.UpdateCursor(fc, fields, sort_fields)
 for i, in_row in enumerate(cursor):
      current_value = in_row.getValue("ColName")
      if not previous_value: 
           previous_value = current_value 
           continue
       #
       # here you have access to the current and previous value
       #

       previous_value = current_value

hoặc, nếu bảng không lớn, có lẽ tôi sẽ xây dựng một từ điển, như d = {a: b} và sau đó trong cập nhật con trỏ truy cập dữ liệu từ từ điển: d.get (a + 1) hoặc d.get (a -1) để làm toán ..


3

Tôi đã chấp nhận câu trả lời của @Hornbydd vì đã dẫn tôi đến một giải pháp từ điển. Kịch bản đính kèm thực hiện các hành động sau:

  1. Lặp lại thông qua FC và điền từ điển với key = OID và value = "MyField" bằng SearchCoder.
  2. Bắt đầu một Cập nhật
  3. Tạo logic để xử lý các hàng đầu tiên và cuối cùng (nghĩa là không có hàng trước hoặc hàng liên tiếp)
  4. Liên kết UpdateCoder hàng với từ điển OID và giá trị trường
  5. Làm việc ...

import arcpy, collections

fc = r'C:\path\to\fc'

# Populate a dictionary with key = OID and value = "a"
names = collections.defaultdict(list)

for name1, name2 in arcpy.da.SearchCursor(fc, ("OBJECTID", "a")):
    names[name1].append(name2)

# Use .values() class to access adjacent rows

with arcpy.da.UpdateCursor(fc, ["OBJECTID", "a", "b"]) as cursor:
    for row in cursor:
        # Get first and last rows for special processing
        if row[0] == names.keys()[0] or row[0] == names.keys()[-1]:
            """Note that the first and last row will need special rules because
             they cannot reference either the previous or next row.  In this case
             the features are skipped"""
            pass

        else:
            """This needs to be corrected because OID = (row[0] - 1)"""
            # Now link the dictionary names with row[0] (i.e. OBJECTID)
            x = names.values()[row[0] - 2]  # e.g. OID 2 (pre)
            y = names.values()[row[0] - 1]  # e.g. OID 3 (current row)
            z = names.values()[row[0]]      # e.g. OID 4 (post)

            # Now do the calculation
            row[2] = x + z
            cursor.updateRow(row)

Tôi không hiểu làm thế nào: if row [0] == name.keys () [0] hoặc row [0] == name.keys () [- 1]: sẽ hoạt động? Các giá trị trong defaultdict không được sắp xếp, phải không?
ianbroad

2

Mô-đun truy cập dữ liệu khá nhanh và bạn có thể tạo một SearchCursorđể lưu tất cả các giá trị từ 'a' vào danh sách, sau đó tạo một UpdateCursorlần lặp qua từng hàng và chọn từ danh sách để cập nhật các hàng 'b' cần thiết. Bằng cách này, bạn không cần phải lo lắng về việc lưu dữ liệu giữa các hàng =)

Vì vậy, một cái gì đó như thế này:

fc = r'C:\path\to\fc'
fields = ["a","b"]
aList = []
index = 0

with arcpy.da.SearchCursor(fc,fields) as cursor:
     for row in cursor:
         aList.append(row[0])    # This saves each value of 'a'
with arcpy.da.UpdateCursor(fc,fields) as cursor:
     for row in cursor:
         if index-1 > 0 AND index+1 <= len(aList):     # Keeps 'b' null if out of list range 
                                                       # or at end of list
             row[1] = aList[index-1]+aList[index+1]
         index += 1

Đây là một giải pháp khá thô sơ nhưng tôi mới sử dụng nó gần đây để giải quyết một vấn đề rất giống nhau. Nếu mã không hoạt động, hy vọng nó sẽ đưa bạn đi đúng hướng!

Chỉnh sửa: Thay đổi lần cuối nếu câu lệnh từ AND thành OR Edit2: Thay đổi trở lại. Ahh áp lực từ bài viết StackExchange đầu tiên của tôi!


Thay vì chỉnh sửa câu trả lời của tôi vào một lần khác, tôi sẽ đưa ra 0,02 đô la cho lý do tại sao tôi nghĩ rằng đây là một giải pháp tốt cho vấn đề. Lặp lại qua các hàng giúp việc lặp lại qua các danh sách thực sự dễ dàng với chỉ số + = 1. Mặc dù tôi không suy nghĩ nhiều về cơ chế của mã, nhưng nó sẽ truyền đạt điểm tôi muốn đưa ra cho bạn. Chúc may mắn!
La Mã

1
Một vài lưu ý: 1) Có thể nhanh hơn cho các bộ dữ liệu lớn nếu bạn sử dụng mức độ hiểu danh sách để điền aListthay vì nối thêm mỗi mục. 2) Sử dụng enumerate()thay vì có một bộ đếm riêng cho chỉ mục.
Paul

-1

Đầu tiên bạn cần một con trỏ tìm kiếm; Tôi không nghĩ bạn có thể nhận được các giá trị với một con trỏ cập nhật. Sau đó, trong mỗi lần lặp, sử dụng aNext = row.next (). GetValue ('a') để lấy giá trị của hàng tiếp theo.

Để có được giá trị của hàng trước tôi sẽ thiết lập một biến bên ngoài vòng lặp for bằng 0. Điều này được cập nhật để bằng với giá trị hàng hiện tại của 'a'. Sau đó, bạn có thể truy cập biến này trong lần lặp tiếp theo.

Điều này sau đó sẽ thỏa mãn phương trình B = A (rowid-1) + A (rowid + 1) của bạn


Bạn không cần phải chuyển sang con trỏ Tìm kiếm để sử dụng getValue. Đây là một phương thức của đối tượng ROW, không phải đối tượng CURSOR.
msayler

Trên thực tế, họ đang sử dụng con trỏ DA, vì vậy tôi không nghĩ getValue thậm chí còn áp dụng. Tôi nghĩ rằng con trỏ DA sử dụng chỉ mục thay thế.
msayler

1
Cập nhật con trỏ có thể đọc cũng như ghi dữ liệu. (Ví dụ, hữu ích để đọc một giá trị từ fieldAvà sử dụng nó để tính giá trị mới cho fieldB.)
Erica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.