Write a function is_balanced(chars) that takes a string and determines
if the various bracketing characters (e.g. ( ), [ ], and { } ) are
balanced returning True when balanced and False when not. In a
properly formatted Python program these characters should always be in
balance unless they are within string literals. Here are some legal
configurations you might find assuming you ignore all of the
characters that are not bracketing characters (we have included extra
spaces for clarity):
{ ( [ ] ) ( [ ( ) ] ) } ( { { ( ) } } [ ] ) ( { [ ] } ) On the other
hand, these are not legal: ( ( [ ] ) # Missing a close parenthesis
) ( # The close parenthesis comes before the open parenthesis
{ ( } ) # The parentheses and braces are improperly nested Your
solution should be based on the insight that a string consisting only
of bracketing characters is balanced if and only if one of the
following conditions holds:
The string is empty The string contains "( )", "{ }" or "[ ]" as a
substring and is balanced if you remove that substring. To do this
you'll want to use the replace string method.
What I have so far:
def is_balanced(chars):
while len(chars) != 0:
if chars[0] == ")":
return True
elif chars[0] == "(":
is_balanced(chars[1:])
return False
I keep getting a time limit exceeded error.
I have a huge JSON file with lots of stuff I don't care about, and I want to filter it down to only the few keys I care about, preserving the structure. I won't bother if the same key name might occur in different paths and I get both of them. I gleaned something very close from the answers to this question, it taught me how to delete all properties with certain values, like all null values:
del(..|nulls)
or, more powerfully
del(..|select(. == null))
I searched high and low if I could write a predicate over the name of a property when I am looking at a property. I come from XSLT where I could write something like this:
del(..|select(name|test("^(foo|bar)$")))
where name/1 would be the function that returns the property name or array index number where the current value comes from. But it seems that jq lacks the metadata on its values, so you can only write predicates about their value, and perhaps the type of their value (that's still just a feature of the value), but you cannot inspect the name, or path leading up to it?
I tried to use paths and leaf_paths and stuff like that, but I have no clue what that would do and tested it out to see how this path stuff works, but it seems to find child paths inside an object, not the path leading up to the present value.
So how could this be done, delete everything but a set of key values? I might have found a way here:
walk(
if type == "object" then
with_entries(
select( ( .key |test("^(foo|bar|...)$") )
and ( .value != "" )
and ( .value != null ) )
)
else
.
end
)
OK, this seems to work. But I still wonder it would be so much easier if we had a way of querying the current property name, array index, or path leading up to the present item being inspected with the simple recusion ..| form.
In analogy to your approach using .. and del, you could use paths and delpaths to operate on a stream of path arrays, and delete a given path if not all of its elements meet your conditions.
delpaths([paths | select(all(IN("foo", "bar") or type == "number") | not)])
For the condition I used IN("foo", "bar") but (type == "string" and test("^(foo|bar)$")) would work as well. To also retain array elements (which have numeric indices), I added or type == "number".
Unlike in XML, there's no concept of attributes in jq. You'll need to delete from objects.
To delete an element of an object, you need to use del( obj[ key ] ) (or use with_entries). You can get a stream of the keys of an object using keys[]/keys_unsorted[] and filter out the ones you don't want to delete.
Finally, you need to invert the result of test because you want to delete those that don't match.
After fixing these problems, we get the following:
INDEX( "foo", "bar" ) as $keep |
del(
.. | objects |
.[
keys_unsorted[] |
select( $keep[ . ] | not )
]
)
Demo on jqplay
Note that I substituted the regex match with a dictionary lookup. You could use test( "^(?:foo|bar)\\z" ) in lieu of $keep[ . ], but a dictionary lookup should be faster than a regex match. And it should be less error-prone too, considering you misused $ and (...) in lieu of \z and (?:...).
The above visits deleted branches for nothing. We can avoid that by using walk instead of ...
INDEX( "foo", "bar" ) as $keep |
walk(
if type == "object" then
del(
.[
keys_unsorted[] |
select( $keep[ . ] | not )
]
)
else
.
end
)
Demo on jqplay
Since I mentioned one could use with_entries instead of del, I'll demonstrate.
INDEX( "foo", "bar" ) as $keep |
walk(
if type == "object" then
with_entries( select( $keep[ .key ] ) )
else
.
end
)
Demo on jqplay
Here's a solution that uses a specialized variant of walk for efficiency (*). It retains objects all keys of which are removed; only trivial changes are needed if a blacklist or some other criterion (e.g., regexp-based) is given instead. WHITELIST should be a JSON array of the key names to be retained.
jq --argjson whitelist WHITELIST '
def retainKeys($array):
INDEX($array[]; .) as $keys
| def r:
if type == "object"
then with_entries( select($keys[.key]) )
| map_values( r )
elif type == "array" then map( r )
else .
end;
r;
retainKeys($whitelist)
' input.json
(*) Note for example:
the use of INDEX
the recursive function, r, has arity 0
for objects, the top-level deletion occurs first.
Here's a space-efficient, walk-free approach, tailored for the case of a WHITELIST. It uses the so-called "streaming" parser, so the invocation would look like this:
jq -n --stream --argjson whitelist WHITELIST -f program.jq input.json
where WHITELIST is a JSON array of the names of the keys to be deleted, and
where program.jq is a file containing the program:
# Input: an array
# Output: the longest head of the array that includes only numbers or items in the dictionary
def acceptable($dict):
last(label $out
| foreach .[] as $x ([];
if ($x|type == "number") or $dict[$x] then . + [$x]
else ., break $out
end));
INDEX( $whitelist[]; .) as $dict
| fromstream(inputs
| if length==2
then (.[0] | acceptable($dict)) as $p
| if ($p|length) == (.[0]|length) - 1 then .[0] = $p | .[1] = {}
elif ($p|length) < (.[0]|length) then empty
else .
end
else .
end )
Note: The reason this is relatively complicated is that it assumes that you want to retain objects all of whose keys have been removed, as illustrated in the following example. If that is not the case, then the required jq program is much simpler.
Example:
WHITELIST: '["items", "config", "spec", "setting2", "name"]'
input.json:
{
"items": [
{
"name": "issue1",
"spec": {
"config": {
"setting1": "abc",
"setting2": {
"name": "xyz"
}
},
"files": {
"name": "cde",
"path": "/home"
},
"program": {
"name": "apache"
}
}
},
{
"name": {
"etc": 0
}
}
]
}
Output:
{
"items": [
{
"name": "issue1",
"spec": {
"config": {
"setting2": {
"name": "xyz"
}
}
}
},
{
"name": {}
}
]
}
I am going to put my own tentative answer here.
The thing is, the solution I had already in my question, meaning I can select keys during forward navigation, but I cannot find out the path leading up to the present value.
I looked around in the source code of jq to see how come we cannot inquire the path leading up to the present value, so we could ask for the key string or array index of the present value. And indeed it looks like jq does not track the path while it walks through the input structure.
I think this is actually a huge opportunity forfeited that could be so easily kept track during the tree walk.
This is why I continue thinking that XML with XSLT and XPath is a much more robust data representation and tool chain than JSON. In fact, I find JSON harder to read even than XML. The benefit of the JSON being so close to javascript is really only relevant if - as I do in some cases - I read the JSON as a javascript source code assigning it to a variable, and then instrument it by changing the prototype of the anonymous JSON object so that I have methods to go with them. But changing the prototype is said to cause slowness. Though I don't think it does when setting it for otherwise anonymous JSON objects.
There is JsonPath that tries (by way of the name) to be something like what XPath is for XML. But it is a poor substitute and also has no way to navigate up the parent (or then sibling) axes.
So, in summary, while selecting by key in white or black lists is possible in principle, it is quite hard, because a pretty easy to have feature of a JSON navigation language is not specified and not implemented. Other useful features that could be easily achieved in jq is backward navigation to parent or ancestor of the present value. Currently, if you want to navigate back, you need to capture the ancestor you want to get back to as a variable. It is possible, but jq could be massively improved by keeping track of ancestors and paths.
I have this jq filter and input:
( ._birthDate.extension[0] | .url, ( .extension[0] | .url, .valueString ), ( .extension[1] | .url, .valueString ) )
{
"_birthDate":{
"extension":[
{
"url":"http://catsalut.gencat.cat/fhir/StructureDefinition/patient-dataBirhtDeath",
"extension":[
{
"url":"country",
"valueString":"724"
},
{
"url":"state",
"valueString":"08"
}
]
}
]
}
}
…which yields the following output:
"http://catsalut.gencat.cat/fhir/StructureDefinition/patient-dataBirhtDeath"
"country"
"724"
"state"
"08"
I wanted to refactor the filter:
( ._birthDate.extension[0] | .url, ( .extension[:2] | .url, .valueString ) )
…but I am getting the following error:
jq: error (at :18): Cannot index array with string "url"
See this demo.
Array/String Slice: .[10:15] [docs]
... Either index may be negative (in which case it counts backwards from the end of the array), or omitted (in which case it refers to the start or end of the array).
So your were first using .extension[0] that ment: take index 0 from .extension where
.extension[:2] means: take index 0 up and including index 2 from .extension
As #pmf already mentiond, the difference is the returned value, an object at first, but an array on the second.
So you can loop over the array using [] to return the .url and .valueString for each object in side the .extension array:
._birthDate.extension[0] | .url, ( .extension[:2][] | .url, .valueString )
Online Demo
However, since .extension is an array with only 2 indexes, the :2 part doesn't do anything useful in your example, so why not simplify it to:
._birthDate.extension[0] | .url, ( .extension[] | .url, .valueString )
Online Demo
If you only need to keep the strings then you can use .. to recursively traverse your document and strings to filter out non-strings yielded along the way:
.. | strings
Demo
I am a relative beginner in Elm. I learned how to recur over records, and to create extensible records. My target application has tree-shaped data, that is to be rendered in several tree views.
In order for Elm to allow recursive models, one needs
a Union type for the children field,
a Maybe in that type definition, and
the lazy anonymous function construct if Json decoding is needed.
So far so good, but I cannot combine recursion with extension. Here below is a minimized version of how far I got. This program is capable of rendering either one of the two example types (Folder and Note), but not both. (see lines commented with -- NOTE and -- FOLDER).
The problem is with the kids function. Elm doesn't allow it to produce two different output types. I am stuck with either duplicating the code, or do without record extensions. Both seems like show-stoppers.
Is there a way to get this working with both, extension and recursion, and without code duplication?
Run on Ellie
module Main exposing (main)
import Html exposing (..)
import Maybe
-- MAIN
main = Html.beginnerProgram
{ model = init
, update = update
, view = view
}
-- MODEL
type alias Model =
{ folder : Folder
, note : Note
}
type alias Node a =
{ a | name : String
, children : Children a
}
type alias Folder =
{ name : String
, children : ChildFolders
}
type alias Note =
{ name : String
, children : ChildNotes
}
type Children a = Children a (Maybe (List (Node a)))
type ChildFolders = ChildFolders (Maybe (List Folder))
type ChildNotes = ChildNotes (Maybe (List Note))
-- INIT
init : Model
init = Model
(Folder "Parent F" someFolders)
(Note "Parent N" (ChildNotes Nothing))
someFolders : ChildFolders
someFolders = ChildFolders
( Just
( [ Folder "Child F1" (ChildFolders Nothing)
, Folder "Child F2" (ChildFolders Nothing)
, Folder "Child F3" (ChildFolders Nothing)
]
)
)
-- UPDATE
type Msg = NoOp
update : Msg -> Model -> Model
update msg model =
case msg of
NoOp -> model
-- VIEW
view : Model -> Html msg
view model =
div []
[ viewBranch model.folder -- FOLDER
-- , viewBranch model.note -- NOTE
]
-- viewBranch : (?) -> Html msg
viewBranch node =
uli
( text node.name
:: ( node
|> kids
|> List.map viewBranch
)
)
uli : List (Html msg) -> Html msg
uli items = ul [] [ li [] items ]
-- kids : (?) -> (?)
kids { children } =
case children of
(ChildFolders data) -> Maybe.withDefault [] data -- FOLDER
-- (ChildNotes data) -> Maybe.withDefault [] data -- NOTE
I am trying to make a GUI application in common lisp with ltk, and there is one thing I just cannot figure out. I know I can set options of ltk widgets with configure, but I cannot figure out a way to read the values.
For example, I create an instance of a canvas with
(make-instance 'canvas :width 400 :height 400)
Then I want to write a method that will use the width and height in some calculations. How do I access these?
I've asked this same question in the ltk user list and got an answer.
In short, the cget function is the counterpart of configure
So, to set the canvas width you do (configure canvas :witdh value) and to retrieve it you do (cget canvas :width).
Regards,
André
(require :ltk)
(in-package :ltk-user)
(defparameter *can*
(make-instance 'canvas :width 400 :height 400))
Indeed the width and height are stored in the string.
I don't know if your can adjust this afterwards. Maybe ask on the ltk mailing list.
#<CANVAS {1005A00C21}>
--------------------
Class: #<STANDARD-CLASS CANVAS>
--------------------
Group slots by inheritance [ ]
Sort slots alphabetically [X]
All Slots:
[ ] INIT-COMMAND = "canvas ~A -height 400 -width 400"
[ ] MASTER = NIL
[ ] NAME = "wc"
[ ] SCROLLREGION-X0 = NIL
[ ] SCROLLREGION-X1 = NIL
[ ] SCROLLREGION-Y0 = NIL
[ ] SCROLLREGION-Y1 = NIL
[ ] WIDGET-CLASS-NAME = "canvas"
[ ] WIDGET-PATH = NIL
[ ] XSCROLL = NIL
[ ] YSCROLL = NIL
[set value] [make unbound]