2010-03-17 5 views
5

Ich habe eine DBF-Tabelle wie unten, die das Ergebnis von eins zu vielen von zwei Tabellen Join ist. Ich möchte eindeutige Zonenwerte von einem Taxlot-ID-Feld haben.verketten multi Werte in einem Datensatz ohne Verdoppelung

Tabellenname: Eingabetabelle
tid ----- Zone
1 ------ A
1 ------ A
1 ------ B
1 ------ C
2 ------ D
2 ------ E
3 ------ C

Erwünschte Ausgangstabelle Tabellenname: Eingabetabelle
tid ----- Zone
1 ------ A, B, C
2 ------ D, E
3 ------ C

Ich habe etwas Hilfe, aber konnte es nicht zum Funktionieren bringen.

+0

Dies ist mit 'Python' und 'Vba' markiert, aber alle den Code an swers sind in Python. Ich kann dafür leicht ein VBA-Beispiel bereitstellen. Können Sie klären, ob die Lösung in einer der beiden Sprachen oder falsch getaggt sein soll? – transistor1

+0

@ Transistor1, gehen Sie voran und bieten Sie die VBA-Lösung. –

Antwort

0

Hier ist ein schnell gemacht Code in Python, die Ihren Bedürfnissen entsprechen, mit minimalen Zappeln.

import collections 

d = collections.defaultdict(list) 

with open("input_file.txt") as f: 
    for line in f: 
     parsed = line.strip().split() 
     print parsed 
     k = parsed[0] 
     v = parsed[2] 
     d[k].append(v) 

for k, v in sorted(d.iteritems()): 
    s = " ----- " 
    v = list(set(v)) # Must be a library function to do this 
    v.sort() 
    print k, s, 
    for j in v: 
     print j, 
    print 

this helps

+1

Verwenden Sie 'collections.defaultdict' und sparen Sie ein wenig Chaos. 'd = defaultdict (list)' und die letzten drei Zeilen der Schleife vereinfachen 'd [k] .append (v)' –

+0

Verwenden Sie auch 'für k in d: v = Elemente [k]' in der zweiten Schleife um es ein Haar einfacher und mehr Python zu machen. –

+0

@ S.Lott Danke. Ich werde dies in meinem Code implementieren! Prost – Morlock

1

denke ich Morlock Antwort nicht die Forderung fallen zu lassen Duplikate nicht erfüllt. Ich würde ein defaultdict (set) verwenden, das automatisch anstelle von defaultdict (list) und somit .add() anstelle von .append() auch dups auslässt.

+0

Es tat :) Aber es ging in den Änderungen verloren. Ich habe eine Zeile 'v = list (set (v)) hinzugefügt, um das zu beheben. Prost – Morlock

3

würde ich my dbf module und defaultdict verwenden, um stark, dass Code zu vereinfachen:

import dbf 
from collections import defaltdict 

inputTbl = dbf.Table(r'c:\temp\input.dbf') 
taxIdZoning = defaultdict(set) 

for record in inputTbl: 
    taxIdZoning[record.tid].add(record.zone) 
inputTbl.close() 

outputTbl = dbf.Table(r'c:\temp\output.dbf', 'tid N(17.0), zones C(20)') 
for tid in sorted(taxIdZoning): 
    record = outputTbl.append() 
    record.tid = tid 
    record.zones = ','.join(sorted(taxIdZoning[tid])) 
outputTbl.close() 

Hinweis: Feldnamen klein geschrieben werden, und ich war nicht sicher genau, wie lange darzustellen, aber hoffentlich 17 Stellen sind genug. :) Ich entschuldige mich für irgendwelche Bugs - schwer zu testen ohne Eingabedateien.

0

Die OP wollte Kommas in der Zonenspalte. Könnte das Ausgangsstück Morlock den Code ändern leicht jene Kommas und vielleicht ein wenig klarer zu erhalten, indem diese eine Zeile für die Ausgabe statt einer expliziten Schleife über v mit:

print k, s, ",".join(v) 

, dass mehr in eine nicht packen Linie (möglicherweise ein Negativ). Die Verwendung von join auf diese Weise ist in Python ziemlich üblich, und IMHO drückt die Absicht deutlicher aus (und ist beim Lesen leichter zu verdauen) als die explizite Schleife.

2

Dies funktionierte für mich mit Microsoft Access VBA und Microsoft Excel VBA. Es ist kein sehr effizienter Code, aber es funktioniert. Ich konnte die resultierende Datei sowohl in Access als auch in Excel öffnen.

Set die sDBF* und sOutDBF* Variablen dies Ihre eigenen Pfade anzupassen.

Sub VBASolution() 
    Dim oRS 
    Dim sConn 
    Dim sDBFPath, sOutDBFPath 
    Dim sDBFName, sOutDBFName 
    Dim oDict 
    Dim curTID, curZone, sZones 
    Dim oConn 
    Dim oFS 
    Dim sTableName 

    sDBFPath = "C:\Path\To\DBFs\" 
    sDBFName = "Input.dbf" 

    sOutDBFPath = "C:\Path\To\DBFs\" 
    sOutDBFName = "RESULTS.dbf" 

    sConn = "Driver={Microsoft dBASE Driver (*.dbf)}; DriverID=277; Dbq=" 
    Set oRS = CreateObject("ADODB.Recordset") 


    oRS.Open "SELECT DISTINCT tid, zone FROM " & sDBFName, sConn & sDBFPath 

    Set oDict = CreateObject("Scripting.Dictionary") 

    Do While Not oRS.EOF 
     curTID = oRS.Fields("tid").Value 
     curZone = oRS.Fields("zone").Value 
     If Not oDict.Exists(curTID) Then 
      oDict.Add curTID, CreateObject("Scripting.Dictionary") 
     End If 
     If Not oDict(curTID).Exists(curZone) Then 
      oDict(curTID).Add curZone, curZone 
     End If 
     oRS.MoveNext 
    Loop 
    oRS.Close 

    Set oRS = Nothing 

    Set oConn = CreateObject("ADODB.Connection") 
    oConn.Open sConn & sOutDBFPath 

    'Delete the resultant DBF file if it already exists. 
    Set oFS = CreateObject("Scripting.FileSystemObject") 
    With oFS 
     If .FileExists(sOutDBFPath & "\" & sOutDBFName) Then 
      .DeleteFile sOutDBFPath & "\" & sOutDBFName 
     End If 
    End With 

    sTableName = oFS.GetBaseName(sOutDBFName) 

    oConn.Execute "CREATE TABLE " & sTableName & " (tid int, zone varchar(80))" 

    Dim i, j 
    For Each i In oDict.Keys 
     curTID = i 
     sZones = "" 
     For Each j In oDict(i) 
      sZones = sZones & "," & j 
     Next 
     sZones = Mid(sZones, 2) 
     oConn.Execute "INSERT INTO " & sTableName & " (tid, zone) VALUES ('" & curTID & "','" & sZones & "')" 
    Next 
    oConn.Close 

    Set oConn = Nothing 
    Set oDict = Nothing 
    Set oFS = Nothing 
End Sub 

EDIT: Für was es wert ist, gilt dies auch für mich gearbeitet, indem sie in eine VBScript VBS-Datei (Text) in Windows XP und das Hinzufügen dieser Zeile zum Ende der Datei einfügen:

Call VBASolution()

Ich weiß nicht, ob Office installiert werden muss oder ob die entsprechenden dbf-Treiber mit Windows geliefert werden.

+1

Wow - ich werde daran erinnert, warum ich Python mag! :) –

+0

LOL Ich bin geneigt, Ihnen zuzustimmen. Danke für die Belohnung - ich bin sehr dankbar. – transistor1

1

statt dessen:

taxIdZoningDict = {} 
searchRows = gp.searchcursor(inputTbl) 
searchRow = searchRows.next() 
while searchRow: 
    if searchRow.TID in taxIdZoningDict: 
     taxIdZoningDict[searchRow.TID].add(searchRow.ZONE) 
    else: 
     taxIdZoningDict[searchRow.TID] = set() #a set prevents dulpicates! 
     taxIdZoningDict[searchRow.TID].add(searchRow.ZONE) 
    searchRow = searchRows.next() 

dies tun:

zones = {} 
for row in gp.searchcursor(inputTbl): 
    zones.setdefault(row.TID, set()) 
    zones[row.TID].add(row.ZONE) 

viel mehr pythonic, mit dem gleichen Ergebnis ;-)

Und dann zur Ausgabe:

for k, v in zones: 
    print k, ", ".join(v) 
Verwandte Themen