Suppose variable b=2 and a stringified json
j = '{"b": "#{b}", "c": null}'
The desired result is:
{
"b" => "2",
"c" => nil
}
My observation:
Since json string contains null, we can not eval it because ruby will say undefined variable or method null. Also, I don't want to replace null with nil.
The only option left is to parse and evaluate.
So I tried the following:
eval(JSON.parse(j).to_s)
which results to
{
"b" => "\#{b}"
}
Please help to achieve desired result?
it should be like this: j = "{'b': '#{b}', 'c': null}"
UPDATE:
Sorry. It should be like this
b = 2
JSON.parse("{ \"b\": \"#{b}\", \"c\": null }")
Related
Suppose I have the following:
table = {a = {1, 2}, b = {3, 4}}
input = "a" -- abstracted away; it's a RV from another function.
You can use table.a[1] to get 1; however, I want to get it from the input variable - which is the return value of another function that I have, which returns the string "a" and not just a.
Now, this is where the error from here comes into play:
When I did table[input], it returned a table object, so then when I tried table[input][1], it had the calling a table error.
Is it possible to get 1 using indexing with the input "a"? If so, could someone let me know how this works? Thanks!
for any table if you use . to index it, it will use a string index.
When you use [] to index it, this means you can use any sort of datatype and it allows you to also use variables.
local someTable = {
a = "hello",
b = "world"
c = "!"
}
-- I can do
print(someTable.a) -- prints "hello"
-- and
print(someTable["b"]) -- prints "world"
-- however
print(someTable[c]) -- will error since there is no c variable
------
-- note that this would be valid
local someVariable = "c"
print(someTable[someVariable]) -- prints "!"
Going back to your case. tbl1 is using [] and using the variable input. However tbl2 is using the string "input" as the index in your table. Your table does not contain "input" as a key, so it returns nil
I hope I understand your question correctly, I apologize if not. If you want to, for example, send a specific part of a table to a user after they specified which key of the table they want then you're already doing everything correctly.
The tbl1 table contains the key "a" part of the main table. You can't print a table, but you can either print specific values by using tbl1[number] or do this:
table = {a = {1, 2}, b = {3, 4}}
input = "b"
tbl1 = table[input]
for _, v in pairs(table) do
print(v)
end
-- Expected output:
-- 3
-- 4
I'm using json-compare gem to compare two different json files.
Example file 1:
{"suggestions": [
{
"id1": 1,
"title1": "Test",
"body1": "Test"
}
]
}
Example file 2:
{"suggestions": [
{
"id2": 1,
"title2": "Test",
"body2": "Test"
}
]
}
The gem works well and spits out a hash that looks like this:
{:update=>
{"suggestions" =>
{:update=>
{0=>
{:append=>
{"id2"=>1, "title2"=>"Test", "body2"=>"Test"},
:remove=>
{"id1"=>1, "title1"=>"Test", "body1"=>"Test"},
}
}
}
}
}
How can I parse this and return all the places where json Keys were changed? For the sake of simplicity, how would I put to the console:
id1 changed to id2
title1 changed to title2
body1 changed to body2
For the purpose of what I'm building I don't need to know changes to the values. I just need to know that id1 became id2, etc.
Except if you are relaying on key ordering there is no way to tell that id1 got replaced by id2 and title2 by title1, or that id1 became title1 and id2 became title2. Sounds like you would need specific logic related to the actual key names (in this example searching for different integer suffixes).
Maybe this can be enough for the purpose:
def find_what_changed_in(mhash, result = [])
result << mhash
return if mhash.keys == [:append, :remove]
mhash.keys.each { |k| find_what_changed_in(mhash[k], result) }
result.last
end
find_what_changed_in(changes)
#=> {:append=>{"id2"=>1, "title2"=>"Test", "body2"=>"Test"}, :remove=>{"id1"=>1, "title1"=>"Test", "body1"=>"Test"}}
Where:
changes = {:update=>
{"suggestions" =>
{:update=>
{0=>
{:append=>
{"id2"=>1, "title2"=>"Test", "body2"=>"Test"},
:remove=>
{"id1"=>1, "title1"=>"Test", "body1"=>"Test"},
...
I would like to return the first element of an array, if the array only contains one value.
Currently, I use:
vals.one? ? vals.first : vals.presence
Thus:
vals = []; vals.one? ? vals.first : vals.presence
# => nil
vals = [2]; vals.one? ? vals.first : vals.presence
# => 2
vals = [2, 'Z']; vals.one? ? vals.first : vals.presence
# => [2, "Z"]
Is there something inbuilt that does this, or does it with a better design consideration?
My use case is specific, involving presenters that know what to expect from the method (which would implement the above code). If those presenters handle all returns as an array, then in most cases (~90%) they will iterate over arrays of size 1 or 0.
You seem to want to handle the case of val array being undefined so...
val.size > 1 ? val : val[0] if defined?(val)
But as has been pointed out it would be better to deliver a consistent argument (always arrays) so the following will deliver the val array or an empty array if undefined
defined?(val) ? val : []
The following code prints:
false
false
true
{{a: b}, {a: b}}
code
import "dart:json" as JSON;
main() {
print(JSON.parse('{ "a" : "b" }') == JSON.parse('{ "a" : "b" }'));
print({ "a" : "b" } == { "a" : "b" });
print({ "a" : "b" }.toString() == { "a" : "b" }.toString());
Set s = new Set();
s.add(JSON.parse('{ "a" : "b" }'));
s.add(JSON.parse('{ "a" : "b" }'));
print(s);
}
I am using json and parsing two equivalent objects, storing them in a Set, hoping they will not be duplicated. This is not the case and it seems to be because the first two lines (unexpectedly?) results in false. What is an efficient way to correctly compare two Map objects assuming each were the result of JSON.parse()?
The recommended way to compare JSON maps or lists, possibly nested, for equality is by using the Equality classes from the following package
import 'package:collection/collection.dart';
E.g.,
Function eq = const DeepCollectionEquality().equals;
var json1 = JSON.parse('{ "a" : 1, "b" : 2 }');
var json2 = JSON.parse('{ "b" : 2, "a" : 1 }');
print(eq(json1, json2)); // => true
For details see this answer which talks about some of the different equality classes: How can I compare Lists for equality in Dart?.
This is a difficult one, because JSON objects are just Lists and Maps of num, String, bool and Null. Testing Maps and Lists on equality is still an issue in Dart, see https://code.google.com/p/dart/issues/detail?id=2217
UPDATE
This answer is not valid anymore, see answer #Patrice_Chalin
This is actually pretty hard, as the == operator on Maps and Lists doesn't really compare keys/values/elements to each other.
Depending on your use case, you may have to write a utility method. I once wrote this quick and dirty function:
bool mapsEqual(Map m1, Map m2) {
Iterable k1 = m1.keys;
Iterable k2 = m2.keys;
// Compare m1 to m2
if(k1.length!=k2.length) return false;
for(dynamic o in k1) {
if(!k2.contains(o)) return false;
if(m1[o] is Map) {
if(!(m2[o] is Map)) return false;
if(!mapsEqual(m1[o], m2[o])) return false;
} else {
if(m1[o] != m2[o]) return false;
}
}
return true;
}
Please note that while it handles nested JSON objects, it will always return false as soon as nested lists are involved. If you want to use this approach, you may need to add code for handling this.
Another approach I once started was to write wrappers for Map and List (implementing Map/List to use it normally) and override operator==, then use JsonParser and JsonListener to parse JSON strings using those wrappers. As I abandoned that pretty soon, I don't have code for it and don't know if it really would have worked, but it could be worth a try.
The matcher library, used from unittest, will do this.
I'm using XMLSlurper. My code is below (but does not work). The problem is that it fails when it hits a node that does not have the attribute "id". How do I account for this?
//Parse XML
def page = new XmlSlurper(false,false).parseText(xml)
//Now save the value of the proper node to a property (this fails)
properties[ "finalValue" ] = page.find {
it.attributes().find { it.key.equalsIgnoreCase( 'id' ) }.value == "myNode"
};
I just need to account for nodes without "id" attribute so it doesn't fail. How do I do that?
You could alternatively use the GPath notation, and check if "#id" is empty first.
The following code snippet finds the last element (since the id attribute is "B" and the value is also "bizz", it prints out "bizz" and "B").
def xml = new XmlSlurper().parseText("<foo><bar>bizz</bar><bar id='A'>bazz</bar><bar id='B'>bizz</bar></foo>")
def x = xml.children().find{!it.#id.isEmpty() && it.text()=="bizz"}
println x
println x.#id
Apprently I can get it to work when I simply use depthFirst. So:
properties[ "finalValue" ] = page.depthFirst().find {
it.attributes().find { it.key.equalsIgnoreCase( 'id' ) }.value == "myNode"
};