Bagaimana cara mengakses baris yang berdekatan dengan kursor?


8

Di tangkapan layar terlampir, atribut berisi dua bidang minat "a" dan "b". Saya ingin menulis skrip untuk mengakses baris yang berdekatan untuk membuat beberapa perhitungan. Untuk mengakses satu baris, saya akan menggunakan UpdateCursor berikut:

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

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

Misalnya, dengan OBJECTID 4, saya tertarik menghitung jumlah nilai baris dalam bidang "a" yang berdekatan dengan baris OBJECTID 4 (yaitu 1 + 3) dan menambahkan nilai itu ke baris OBJECTID 4 di bidang "b". Bagaimana saya bisa mengakses baris yang berdekatan dengan kursor untuk membuat perhitungan semacam ini?

masukkan deskripsi gambar di sini

Jawaban:


7

Jika ini saya, saya akan melewati tabel sekali membuat kamus di mana kuncinya adalah OBJECTID dan item adalah nilai dalam bidang "a". Saya kemudian akan melangkah melalui tabel dengan kursor pembaruan yang mendapatkan OBJECTID dan dari sana saya bisa mendapatkan nilai-nilai yang berdekatan dari kamus, menjumlahkannya dan menulisnya kembali ke bidang "b".

Tetapi dalam tangkapan layar Anda memiliki kasing khusus untuk baris 3 dan 8 karena hanya memiliki satu baris yang berdekatan. Apa yang Anda inginkan untuk ini?


+1 Ini adalah solusi yang baik karena dapat digunakan dengan cara yang menghormati model data relasional. Dalam model ini, urutan pemrosesan baris tidak ditentukan, sehingga prosedur apa pun yang bergantung pada asumsi bahwa mereka akan diulang dalam urutan yang sama yang ditampilkan dalam tampilan tabel harus dianggap tidak dapat diandalkan. Dengan menggunakan kunci apa saja - bukan hanya OBJECTID- solusi ini dapat mengidentifikasi tetangga sesuai dengan nilai-nilai kunci itu. Namun, kamus biasanya tidak mendukung pencarian "berikutnya" atau "sebelumnya". Anda membutuhkan sesuatu seperti Trie .
whuber

4

Saat memutar di atas baris, Anda harus melacak nilai sebelumnya. Ini adalah salah satu cara untuk melakukannya:

 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

atau, jika tabelnya tidak besar, saya mungkin akan membangun kamus, seperti d = {a: b} dan kemudian di perbarui data akses kursor dari kamus: d.get (a + 1) atau d.get (a -1) untuk melakukan perhitungan matematika ..


3

Saya telah menerima jawaban @Hornbydd untuk membimbing saya menuju solusi kamus. Skrip terlampir melakukan tindakan berikut:

  1. Loop melalui FC dan isi kamus dengan kunci = OID dan nilai = "MyField" menggunakan SearchCursor.
  2. Mulai UpdateCursor
  3. Buat logika untuk menangani baris pertama dan terakhir (yaitu di mana tidak ada baris sebelumnya atau berturut-turut)
  4. Tautkan baris UpdateCursor ke kamus OID dan nilai Bidang
  5. Lakukan pemrosesan ...

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)

Saya tidak mengerti caranya: jika baris [0] == names.keys () [0] atau baris [0] == names.keys () [- 1]: akan berfungsi? Nilai-nilai dalam defaultdict tidak diurutkan, bukan?
ianbroad

2

Modul Akses Data cukup cepat dan Anda dapat membuat a SearchCursoruntuk menyimpan semua nilai dari 'a' ke dalam daftar kemudian membuat a UpdateCursoruntuk beralih melalui setiap baris dan pilih dari daftar untuk memperbarui baris 'b' yang diperlukan. Dengan cara ini Anda tidak perlu khawatir tentang menyimpan data di antara baris =)

Jadi sesuatu seperti ini:

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

Ini adalah solusi yang cukup kasar tetapi saya baru saja menggunakannya untuk mengatasi masalah yang sangat mirip. Jika kode tidak berfungsi semoga kode ini menempatkan Anda di jalur yang benar!

Edit: Diubah terakhir jika pernyataan dari DAN ke ATAU Edit2: Diubah kembali. Ahh tekanan dari posting StackExchange pertama saya!


Alih-alih mengedit jawaban saya lain kali saya akan memberikan $ 0,02 untuk alasan saya pikir ini adalah solusi yang baik untuk masalah ini. Iterasi melalui baris membuatnya sangat mudah untuk beralih melalui daftar juga dengan indeks + = 1. Meskipun saya tidak banyak memikirkan mekanisme kode, itu harus menyampaikan poin yang ingin saya sampaikan kepada Anda. Semoga berhasil!
Roman

1
Beberapa catatan: 1) Ini bisa lebih cepat untuk dataset besar jika Anda menggunakan pemahaman daftar untuk mengisi aListalih-alih menambahkan setiap entri. 2) Gunakan enumerate()alih-alih memiliki penghitung terpisah untuk indeks.
Paul

-1

Pertama, Anda membutuhkan kursor pencarian; Saya tidak berpikir Anda bisa mendapatkan nilai dengan kursor pembaruan. Kemudian di setiap iterasi gunakan aNext = row.next (). GetValue ('a') untuk mendapatkan nilai dari baris berikutnya.

Untuk mendapatkan nilai dari baris sebelumnya saya akan mengatur variabel di luar for for sama dengan nol. Ini diperbarui untuk sama dengan nilai baris saat ini dari 'a'. Anda kemudian dapat mengakses variabel ini di iterasi berikutnya.

Ini kemudian akan memenuhi persamaan Anda dari B = A (rowid-1) + A (rowid + 1)


Anda tidak perlu beralih ke kursor Pencarian untuk menggunakan getValue. Ini adalah metode objek ROW, bukan objek CURSOR.
msayler

Sebenarnya, mereka menggunakan kursor DA, jadi saya pikir getValue bahkan tidak berlaku. Saya pikir kursor DA menggunakan indeks sebagai gantinya.
msayler

1
Pembaruan kursor dapat membaca serta menulis data. (Berguna, misalnya, untuk membaca nilai dari fieldAdan menggunakannya untuk menghitung nilai baru untuk fieldB).
Erica
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.