Отображение элементов в массиве - PullRequest
0 голосов
/ 17 февраля 2020

Надеюсь, что это очень просто, но я просто не понимаю, как это сделать.

Я хочу с помощью go отобразить элементы в массиве в более чистую версию. Например, из данных ниже

data = [
  {
    "some": "value",
    "another": "mvalue",
    "dont": "want"
  },
  {
    "some": "value1",
    "another": "mvalue1",
    "dont": "want1"
  },
  {
    "some": "value2",
    "another": "mvalue2",
    "dont": "want2"
  }
]

Я хочу превратить данные в

result = [
  {
    "some": "value",
    "another": "mvalue"
  },
  {
    "some": "value1",
    "another": "mvalue1"
  },
  {
    "some": "value2",
    "another": "mvalue2"
  }
]

Два ближайших, я думаю, у меня есть

result1 = cleaned {
    cleaned := {d | 
        d := {
            "some": data[_].some,
            "another": data[_].another
        }
    }
}

result2 = cleaned {
    d := data[_]
    cleaned := {
        "some": p.some,
        "another": p.another
    }
}

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

TLDR; Если поля имеют статус c и вы можете легко перечислить их, оба ваших решения верны почти (см. Ниже объяснение, почему они неверны.) Вот правильный способ сделать это:

result = [
  mapped |
    original := data[_]
    mapped := {"some": original["some"], "another": original.another}
]

Немного более элегантный вариант - определить поля для включения или исключения, как в примере @ eephillip. Например:

result = [
  mapped |
    original := data[_]
    mapped := {k: v |
      some k
      v := original[k]
      not exclude[k]}
]

exclude = {"dont", "dont2"}  # defines a SET of keys to exclude

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

Вот интерактивный пример: https://play.openpolicyagent.org/p/P6wPd3rudJ


Два замечания об исходном решении.

1. result1 не выполняет итерацию по data правильно

{d | 
  d := {
    "some": data[_].some,        # problem: _ is a different variable in each expression
    "another": data[_].another
  }
}

Концептуально каждое вхождение _ является уникальной переменной. Если вы явно объявите переменные, проблема станет более очевидной:

# note: this is still wrong
{d | 
  some i, j
  d := {
    "some": data[i]["some"],
    "another": data[j].another
  }
}

Если вы запустите это, вы обнаружите, что он производит перекрестный продукт (а это не то, что вам нужно). Вы хотите, чтобы поля "some" и "another" выбирались из одного и того же объекта, подобного этому:

{d | 
  some i
  d := {
    "some": data[i]["some"],
    "another": data[i].another
  }
}

Конечно, поиск уникальных имен переменных может быть проблемой, так что вы можете использовать _. Только не путайте множественные переменные _ со ссылкой на одно и то же значение. Мы можем переписать оператор для использования _ следующим образом:

{d | 
  obj := data[_]
  d := {
    "some": obj["some"],
    "another": obj.another
  }
}

result2 близко, но может назначать несколько значений (которых следует избегать)

result2 = cleaned {
    d := data[_]
    cleaned := {               # problem: there could be multiple values for 'cleaned'
        "some": d["some"],
        "another": d.another
    }
}

Правила форму NAME = VALUE { BODY } присвойте VALUE NAME, если утверждения в BODY выполнены. Если вы пропустите BODY, то есть напишите NAME = VALUE, тогда BODY по умолчанию будет true (что всегда выполняется.)

В приведенном выше примере:

  • NAME это result2
  • VALUE это cleaned
  • BODY это d := data[_]; cleaned := {...}

В Re go, мы Назовите эти правила «полными правилами» . Полные правила - это просто операторы IF-THEN, которые присваивают одно значение переменной. Часть «IF» - это тело правила, а часть «THEN» - это назначение. Следует избегать написания правил, которые могут присваивать значения MULTIPLE одной и той же переменной, поскольку это может привести к ошибке времени оценки. Например:

# do not do this
result = v { 
   v := data[_]   # if 'data' is [1,2,3] then what is the value of 'result'? Hint: There is more than one answer.
}

Если вы хотите присвоить значения MULTIPLE переменной, вы можете определить «частичное правило» Например:

result[v] {       # result is a SET.
   v := data[_]
}
1 голос
/ 18 февраля 2020

Как насчет выполнения отклонения ключевого имени во время понимания? Вероятно, более элегантный способ сделать это, но может быть полезным.

package play

reject(key) = result {
    remove := [ "dont", "someotherthing" ]
    result :=  key == remove[_]
}

result = d {
    d := [ obj | 
           val := input.data[_]; 
           obj := { k: v | 
                    v := val[k] 
                    not reject(k)
                  }
          ] 
 }

https://play.openpolicyagent.org/p/1A3DNLiNfj

...