2016-09-13 5 views
0

Jetzt enthält, dies zu jq: select only an array which contains element A but not element B etwas ähnlich ist, aber es für mich irgendwie nicht funktioniert (was wahrscheinlich ist meine Schuld) ... ;-)JQ Elemente auswählen, mit Array nicht String

Also hier ist, was wir haben :

[ { 

     "employeeType": "student", 
     "cn": "dc8aff1", 
     "uid": "dc8aff1", 
     "ou": [ 
      "4210910", 
      "4210910 #Abg", 
      "4210910 Abgang", 
      "4240115", 
      "4240115 5", 
      "4240115 5\/5" 
     ] 
    }, 
    { 
     "employeeType": "student", 
     "cn": "160f656", 
     "uid": "160f656", 
     "ou": [ 
      "4210910", 
      "4210910 3", 
      "4210910 3a" 
     ] } ] 

ich möchte alle Elemente auszuwählen, in dem ou tut nicht eine bestimmte Zeichenfolge enthalten, sagen Sie „4.210.910 3a“ oder - was noch besser wäre - wo ou ein bestimmtes kein Mitglied enthalten Liste der Zeichenfolgen.

Antwort

1

Wenn es zu möglichen Änderungen der Eingaben kommt, sollten Sie es zu einem Parameter für Ihren Filter machen, anstatt ihn hart zu codieren. Auch die Verwendung von contains funktioniert möglicherweise nicht für Sie im Allgemeinen. Es führt den Filter rekursiv aus, so dass sogar Teilzeichenfolgen übereinstimmen, die möglicherweise nicht bevorzugt werden.

Zum Beispiel:

["10", "20", "30", "40", "50"] | contains(["0"]) 

ist true

ich es so schreiben würde:

$ jq --argjson ex '["4210910 3a"]' 'map(select(all(.ou[]; $ex[]!=.)))' input.json 
1

Diese Antwort befasst sich mit dem Fall, in dem .ou ein Array ist und wir eine andere gegeben Array von verbotenen Strings.

Aus Gründen der Klarheit, lassen Sie uns einen Filter definieren, intersectq(a;b), die wahr zurück iff die Arrays ein Element gemeinsam haben:

def intersectq(a;b): 
    any(a[]; . as $x | any(b[]; . == $x)); 

Dies ist effektiv eine Schleife-within-a-Schleife, sondern auch wegen der . Semantik von any/2, wird die Berechnung beendet, sobald eine Übereinstimmung gefunden wurde (*)

$ ex Unter der Annahme, die Liste der Ausnahmen ist, dann wird der Filter wir das Problem zu lösen wäre verwenden:

map(select(intersectq(.ou; $ex) | not)) 

Zum Beispiel könnten wir einen Aufruf an den von Jeff vorgeschlagenen Linien verwenden:

$ jq --argjson ex '["4210910 3a"]' -f myfilter.jq input.json 

Nun könnte man fragen: Warum verwenden Sie die Any-in-eine Doppelschleife statt [] - innerhalb-alle Doppel. Schleife? Die Antwort ist die Effizienz, wie sie mit debug zu sehen:

$ jq -n '[1,2,3] as $a | [1,1] as $b | all($a[]; ($b[] | debug) != .)' 
["DEBUG:",1] 
["DEBUG:",1] 
false 

$ jq -n '[1,2,3] as $a | [1,1] as $b | all($a[]; . as $x | all($b[]; debug | $x != .))' 
["DEBUG:",1] 
false 

(*) Fußnote

Natürlich intersectq/2 wie hier definiert ist noch O (m * n) und somit ineffizient, aber der Hauptpunkt Dieser Post soll den Nachteil der Doppelschleife ".

0

Hier ist eine Lösung, die das .ou Element jedes Element der Eingabeprüfungen unter Verwendung von foreach und enthält.

["4210910 3a"] as $list # adjust as necessary 

| .[] 
| foreach $list[] as $e (
    .; .; if .ou | contains([$e]) then . else empty end 
) 

EDIT: Ich weiß jetzt, einen Filter der Form kann foreach E as $X (.; .; R) fast immer als E as $X | R neu geschrieben werden, so ist die oben wirklich nur

["4210910 3a"] as $list 
| .[] 
| $list[] as $e 
| if .ou | contains([$e]) then . else empty end 
Verwandte Themen