Python Array JSON (dumps) - arrays

Google App Engine, Python27
I am trying to encode a python array of strings to a JSON string to send to the client. I created a working solution, which requires me to manually create a string version of the array and call dumps on it from python, but I don't believe it should be necessary:
def get_json(cls):
name_query = cls.query()
array_string = "["
index = 1
for name in name_query:
array_string += '"' + name.key.id() + '"'
if index < name_query.count():
array_string += ", "
index += 1
array_string += "]"
return json.dumps(array_string)
>> "[\"Billy\", \"Bob\"]"
For my second attempt, I tried calling "dumps" on a python array, which I believe should be a working solution; instead, I have to call dumps twice:
# (bad output)
def get_json(cls):
name_query = cls.query()
name_array = []
for name in name_query:
name_array.append(name.key.id())
return json.dumps(name_array)
>> ["Billy", "Bob"]
# (working output)
def get_json(cls):
name_query = cls.query()
name_array = []
for name in name_query:
name_array.append(name.key.id())
return json.dumps(json.dumps(name_array)))
>> "[\"Billy\", \"Bob\"]"
Even though I have a working solution, is there a better way and why does calling dumps on a python array not give the correct output?

The first function is working fine; it's outputting a valid JSON string. I think the confusion for you is that it's not surrounded in double-quotes, but that's just because you're printing the output of the function.
It's returning a string containing a JSON list, not a Python list object:
>>> def get_json():
... x = ["Billy", "Bob"]
... return json.dumps(x)
...
>>> print get_json()
["Billy", "Bob"]
>>> print repr(get_json())
'["Billy", "Bob"]' # It's a string, not a list
>>> type(get_json())
<type 'str'> # See? Type is str
When you call json.dumps twice, you're just wrapping the Python string returned by the first json.dumps call in double-quotes, and the double-quotes that were inside the array get escaped, because they're embedded in one big JSON string now, instead of being used as quotes around JSON strings inside a JSON array.
>>> print repr(json.dumps(get_json()))
'"[\\"Billy\\", \\"Bob\\"]"'

Related

Why is Groovy not converting an array of Strings into JSON correctly?

I have a String that has an array of Strings which I converted that into a groovy array (with the split function), and then I am using JsonOutput.toJson to convert that array into JSON like so.
def orignal = "[ \"Backsplash\", \"Kitchen Wall\", \"Wall Tile\", \"Bathroom Wall\"]"
def originalAsArray = orignal.toString().split(",")
JsonOutput.toJson(originalAsArray)
The output of this is
["[ \"Backsplash\""," \"Kitchen Wall\""," \"Wall Tile\""," \"Bathroom Wall\"]"]
which is an array with a single String element where I was expecting an element with multiple String elements like so
[ "Backsplash", "Kitchen Wall"," "Wall Tile"," "Bathroom Wall"]
Why is the array not being converted as I expected?
// Given the original String
def original = '[ "Backsplash", "Kitchen Wall", "Wall Tile", "Bathroom Wall"]'
// The easiest way of parsing it (as it's valid JSON already)
def list = new groovy.json.JsonSlurper().parseText(original)
// And we get a list of Strings:
assert list.size() == 4
assert list[0] == 'Backsplash'
assert list[3] == 'Bathroom Wall'
// To put this back into a JSON string, we just need to do:
def output = groovy.json.JsonOutput.toJson(list)
// Which gives us the string as expected:
assert output == '["Backsplash","Kitchen Wall","Wall Tile","Bathroom Wall"]'

efficient way to get string between the two words

I have a list of strings as:
strings= ['stackasdf:5;iwantthis123jasdoverflow','iwantthistoo','asdf:5;python123jasd']
Now, I want to print strings both in between two substrings(start=asdf:5; end=123jasd) and which are not.
output expected:
iwantthis
iwantthistoo
python
What I've done is:
import re
start = 'asdf:5;'
end = '123jasd'
for i in strings:
t=i[len(start):-len(end)]
if t:
print (t)
else:
print (i)
df:5;iwantthis123jasdo
iwantthistoo
python
I'm not getting the desired output as expected.
Using a regex approach we can try:
strings = ['stackasdf:5;iwantthis123jasdoverflow','iwantthistoo','asdf:5;python123jasd']
output = [re.findall(r'asdf:5;(.*?)123jasd', x)[0] if re.search(r'asdf:5(.*?)123jasd', x) else x for x in strings]
print(output) # ['iwantthis', 'iwantthistoo', 'python']
You can just use a simple for each loop and if statement to print out the correct substring of each element in the array:
strings= ['stackasdf:5;iwantthis123jasdoverflow','iwantthistoo','asdf:5;python123jasd']
for word in strings:
if "asdf:5;" in word and "123jasd" in word:
ind1 = word.index("asdf:5;")
ind2 = word.index("123jasd")
print(word[ind1+7:ind2])
else:
print(word)
output:
iwantthis
iwantthistoo
python
Use replace function & split?
strings = ['stackasdf:5;iwantthis123jasdoverflow',
'iwantthistoo',
'asdf:5;python123jasd']
for i in strings:
c = '\n' # c may be any character that is not present in your strings
i = i.replace('asdf:5;', c).replace('123jasd', c).split(c)
print(i[0] if len(i) == 1 else i[1])
print(f'{strings = }') # to show that I am not changing the original list.
Output:
iwantthis
iwantthistoo
python
strings = ['stackasdf:5;iwantthis123jasdoverflow', 'iwantthistoo', 'asdf:5;python123jasd']

How to find a specific value in a nested array?

I'm trying to figure out how to place a value into one of three arrays and then shuffle those arrays and have the program output the index location of the value.
Here is what I have so far:
# The purpose of this program is to randomly place the name Zac
# in one of three arrays and return the array number and position of
# Zac
A1 = ["John","Steve","Frank","Charles"]
A2 = ["Sam","Clint","Stuart","James"]
A3 = ["Vic","Jim","Bill","David"]
n = [A1,A2,A3]
name = "Zac"
def placename(title, namelist)
mix = rand(2)
namelist[mix] << title
namelist.shuffle
return namelist
end
allnames = [] << placename(name, n)
def findname(allnames, key)
allnames.each do |i|
until allnames[i].include?(key) == true
i+=1
end
location = allnames[i].find_index(key)
puts "The location and value of #{key} is #{location}"
end
end
findname(allnames, name)
At the moment I'm getting a "undefined method for Nil Class" error (no method error)
Can someone please clarify what I'm doing wrong with this or if there is a more effective way of going about this? Thanks in advance!!
Your approach assumes that in the block starting...
allnames.each do |i|
... that i will contain the index of the allnames element. This isn't true. i will contain the VALUE (contents) of the element.
What you could try as an alternative is...
allnames.each_with_index do |_value, i|
or, you can do...
allnames.each do |value|
and then replace all references to allnames[i] with value
another problem is that...
allnames = [] << placename(name, n)
puts the returned array of arrays inside ANOTHER array. I think what you want to do is..
allnames = placename(name, n)
I modified the last fewlines. I hope this is what you wanted
allnames = placename(name, n)
def findname allnames, key
r = allnames.map.with_index{|x,i|x.include?(key) ? i : p}-[p]
puts "The location of value #{key} is array number #{r[0]} and item number #{allnames[r[0]].index(key)}"
end
findname(allnames, name)
Edit: Randomization
To get randomized array number and item number you have to do the following
def placename(title, namelist)
mix = rand(3) # Since the number of arrays (nested within) is 3 we can use 3 instead of 2
namelist[mix] << title
namelist.map!{|x|x.shuffle}.shuffle! # Shuffling each item and the whole array in place.
return namelist
end
Assuming you want to modify the array in place, I'd do it like this:
# insert name into random subarray
def insert_name name
subarray_idx = rand #name_arrays.size
subarray = #name_arrays[subarray_idx]
insertion_idx = rand subarray.size
#name_arrays[subarray_idx].insert insertion_idx, name
sprintf '"%s" inserted at #name_arrays[%d][%d]',
name, subarray_idx, insertion_idx
end
# define starting array, then print & return the
# message for further parsing if needed
#name_arrays = [
%w[John Steve Frank Charles],
%w[Sam Clint Stuart James],
%w[Vic Jim Bill David],
]
p(insert_name 'Zac')
This has a few benefits:
You can inspect #name_arrays to validate that things look the way you expect.
The message can be parsed with String#scan if desired.
You can modify #insert_name to return your indexes, rather than having to search for the name directly.
If you don't capture the insertion index as a return value, or don't want to parse it from your message String, you can search for it by leveraging Enumerable#each_with_index and Array#index. For example:
# for demonstration only, set this so you can get the same
# results since the insertion index was randomized
#name_arrays =
[["John", "Steve", "Frank", "Charles"],
["Sam", "Clint", "Stuart", "James"],
["Vic", "Jim", "Zac", "Bill", "David"]]
# return indices of nested match
def find_name_idx name
#name_arrays.each_with_index
.map { [_2, _1.index(name)] }
.reject { _1.any? nil }
.pop
end
# use Array#dig to retrieve item at nested index
#name_arrays.dig *find_name_idx('Zac')

Ruby Iterating Through Array for Method Names

I have an object that I want to output a bunch of methods' results from. I have an array of method names and want to iterate through them:
img = Magick::Image::read('/Users/rich/Projects/imagemagick/orig/IMG_4677.jpg')[0]
atts = "background_color base_columns base_filename base_rows bias black_point_compensation".split(' ')
atts.each do |i|
puts img.i # problem evaluating i
end
I have tried string interpolation and eval but I can't get it to realize it's a method call.
Is there a way I can apply an array as method names to an object?
Try using public_send:
atts = "upcase downcase".split
atts.each do |i|
puts 'hEllO'.public_send(i)
end
#HELLO
#hello

Why does my Ruby test return only one word instead of the entire auth_name string?

Here is the code I have:
def initialize (htaccess_file_content)
#htaccess_hash = Hash.new
htaccess_file_content.each_line do | line |
#commands = line.split
#htaccess_hash[#commands[0]] = #commands[1]
end
end
def auth_name
#htaccess_hash['AuthName'].gsub(/''/,"")
end
This is my spec:
describe WebServer::Htaccess do
let(:auth_name) { "This is the auth_name" }
end
describe '#auth_name' do
it 'returns the AuthName string' do
expect(htaccess_user.auth_name).to eq auth_name
end
end
My Ruby code is not returning the whole string and I don't know why. Here is the error message from the failed test:
Failure/Error: expect(htaccess_user.auth_name).to eq auth_name
expected: "This is the auth_name"
got: "\"This"
(compared using ==)
Use an Array Slice
#htaccess_hash[#commands[0]] = #commands[1]
String#split splits on whitespace by default, so when you specify #commands[1] you are assigning only a single array element (the word "This") as your hash value. The simplest thing you can do is to change your subscript to an Array#slice to assign all the remaining elements as the hash value, e.g.:
#commands = line.split
#htaccess_hash[#commands[0]] = #commands[1..-1]

Resources