2016-09-13 22 views
0

Теперь, это несколько похоже на jq: select only an array which contains element A but not element B, но это как-то не работает для меня (что, вероятно, моя вина) ... ;-)JQ выбора элементов с массивом не содержащий строку

Итак, вот что мы имеем :

[ { 

     "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" 
     ] } ] 

Я хотел бы, чтобы выбрать все элементы, где НУ делает не содержат определенную строку, скажем, «4210910 3a» или - что было бы еще лучше - где НУ не содержит какого-либо члена данность список строк.

ответ

1

Когда дело доходит до возможного изменения ввода, вы должны сделать его параметром для своего фильтра, а не жестко кодировать его. Кроме того, использование contains может не сработать для вас в целом. Он запускает фильтр рекурсивно, поэтому даже подстроки будут соответствовать, что может быть не предпочтительным.

Например:

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

является true

Я бы написал так:

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

Этот ответ рассматривается случай, когда .ou является массивом, и мы дали другое массив запрещенных строк.

Для наглядности, давайте определим фильтр, intersectq(a;b), который будет возвращать истинным тогда и только тогда массивы имеют общий элемент:

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

Это эффективно петля-в-петлю, но из-за . семантика any/2, вычисление прекратится после матча был найден (*)

Предполагая $ ех список исключений, то фильтр мы могли бы использовать, чтобы решить эту проблему будет:

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

Например, мы могли бы использовать вызов вдоль линий, предложенных Джефф:

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

Теперь вы можете спросить: почему использовать любую-внутри-любую двойную петлю, а не [] - в-все двойные. цикл? Ответ эффективность, как можно видеть с помощью debug:

$ 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 

(*) Сноска

Конечно intersectq/2, как определено здесь, по-прежнему O (м * п) и, таким образом, неэффективна, но главная точка этот пост должен подчеркнуть недостаток двойного цикла. [] - внутри всего.

0

Вот это решение, которое проверяет .ou элемента каждого элемента ввода с использованием Еогеаспа и содержат.

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

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

EDIT: Теперь я понимаю, фильтр формы foreach E as $X (.; .; R) почти всегда можно переписать в виде E as $X | R так выше на самом деле просто

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