Groovy Convert string data to map - arrays

I have a large String which I want to convert to a Map in groovy.
The String data is an array of key value pairs each key and value is enclosed in square brackets [] and separated by commas. Full data string here: https://pastebin.com/raw/4rBWRzMs
Some of the values can be empty e.g. '[]' or a list of values containing , and : characters e.g.
[1BLL:220,1BLE:641,2BLL:871,2BLE:475,SW:10029,KL:0,KD:78,ODT:148,AVB:358]
I only want to split on these characters if they are not enclosed in square brackets [].
The code I have tried but breaks when there are a list of values. Is there a better way? Thanks.
String testData="[[DEVICE_PROVISIONED]: [1], [aaudio.hw_burst_min_usec]: [2000],[debug.hwui.use_buffer_age]: [false], [ro.boot.boottime][1BLL:220,1BLE:641,2BLL:871,2BLE:475,SW:10029,KL:0,KD:78,ODT:148,AVB:358], ro.boot.hardware]: [walleye],[dev.mnt.blk.postinstall]: [],[ro.boot.usbradioflag]: [0], [ro.boot.vbmeta.avb_version]: [1.0], [ro.boot.vbmeta.device]: [/dev/sda18], [ro.boot.vbmeta.device_state]: [unlocked]]"
def map = [:]
testData.replaceAll('\\[]','null').replaceAll("\\s","").replaceAll('\\[','').replaceAll(']','').split(",").each {param ->
def nameAndValue = param.split(":")
map[nameAndValue[0]] = nameAndValue[1]
}

I'd grep the key-value-tuples from that format and build a map from
there. Once this is done it's easier to deal with further
transformations. E.g.
def testData="[DEVICE_PROVISIONED]: [1], [aaudio.hw_burst_min_usec]: [2000],[debug.hwui.use_buffer_age]: [false], [ro.boot.boottime]: [1BLL:220,1BLE:641,2BLL:871,2BLE:475,SW:10029,KL:0,KD:78,ODT:148,AVB:358], [ro.boot.hardware]: [walleye],[dev.mnt.blk.postinstall]: [],[ro.boot.usbradioflag]: [0], [ro.boot.vbmeta.avb_version]: [1.0], [ro.boot.vbmeta.device]: [/dev/sda18], [ro.boot.vbmeta.device_state]: [unlocked]"
def map = [:]
(testData =~ /\s*\[(.*?)\]\s*:\s*\[(.*?)\]\s*,?\s*/).findAll{ _, k, v ->
map.put(k,v)
}
println map.inspect()
// → ['DEVICE_PROVISIONED':'1', 'aaudio.hw_burst_min_usec':'2000', 'debug.hwui.use_buffer_age':'false', 'ro.boot.boottime':'1BLL:220,1BLE:641,2BLL:871,2BLE:475,SW:10029,KL:0,KD:78,ODT:148,AVB:358', 'ro.boot.hardware':'walleye', 'dev.mnt.blk.postinstall':'', 'ro.boot.usbradioflag':'0', 'ro.boot.vbmeta.avb_version':'1.0', 'ro.boot.vbmeta.device':'/dev/sda18', 'ro.boot.vbmeta.device_state':'unlocked']
Note that I have fixed some syntax in the testData and removed the outer
[]. If the original testData are actually containing invalid syntax
to the rules given, then this will not work.

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

Using flatten! on an array of arrays not working

I am building a script that takes in a column from a CSV that can contain 0 or more ID numbers. I have created an array of the column, however, since some cells have no ID number and some have multiple,I have an array of arrays.
I want to create an array where each element is a single ID (i.e split the IDs from each element in the array to a single element).
Here is my code so far:
require 'csv'
class MetadataTherapyParser
def initialize (csv)
#csv = csv
end
def parse_csv
therapy_array = []
CSV.foreach(#csv) do |csv_row|
therapy_array << csv_row[0]
end
therapy_array
end
def parse_therapies(therapy_array)
parsed_therapy_array = therapy_array.flatten!
end
end
metadata_parse = MetadataTherapyParser.new ("my_path.csv")
therapy_array = metadata_parse.parse_csv
metadata_parse.parse_therapies(therapy_array)
p therapy_array
However, the output is still an array of arrays. I am thinking it may have something to do with nil values? I have tried looking for answers online to no avail.
If you could give me some advice as how to fix this problem, it would be greatly appreciated!
Thank you in advance.
EDIT
I have posted a snippet of my output below. It still appears to be a nested array.
[nil, nil, "57e923a0f5c3c85c9200052b, 58b828f4f5c3c806490046a6", "57e923a0f5c3c85c9200052b, 4ffaf15af758862fb10155e3, 58b828f4f5c3c806490046a6", "57e923a0f5c3c85c9200052b, 4ffaf15af758862fb10155e3, 58b828f4f5c3c806490046a6", nil, nil, nil, nil, nil, "5f9176e50cf19216d6da9289", "6082f6bd0cf19225863fc985", "6082f6fd0cf192258d3fce0e", "6082f69e0cf19225ac3fc551", "6082f6a60cf19225a23fd3e4, 6082f6d30cf192258d3fce0a, 6082f7fa0cf19225953fc77c"]
You say you have "an array of arrays" but your example array is "57e923a0f5c3c85c9200052b, 4ffaf15af758862fb10155e3, 58b828f4f5c3c806490046a6" ... that's not an array. That's a string. You probably want to split strings that have commas into separate array elements.
So instead of
therapy_array << csv_row[0]
try instead
therapy_array << csv_row[0].to_s.split(',').map(&:strip)
the flatten is working perfectly. the issue you are having is that you have lots of strings in your output, with commas in them.
having not got a copy of your CSV, I'm going to assume that it has been parsed correctly, and that you do want to keep the contents of the first cell as it is:
def parse_therapies(therapy_array)
parsed_therapy_array = therapy_array.map { |x| x && x.split(/,/) }.flatten.compact
therapy_array.replace(parsed_therapy_array)
end
this will also remove all the nil elements, assuming you don't want them, using the compact procedure.

Recursively apply a function to elements of an array spark dataFrame

I wrote the following function which concatenates two strings and adds them in a dataframe new column:
def idCol(firstCol: String, secondCol: String, IdCol: String = FUNCTIONAL_ID): DataFrame = {
df.withColumn(IdCol,concat(col(firstCol),lit("."),col(secondCol))).dropDuplicates(IdCol)
}
My aim is to replace the use of different strings by one array of strings, and then define the new column from the concatenation of these different elements of the array. I am using an array in purpose in order to have a mutable data collection in case the number of elements to concatenate changes.
Do you have any idea about how to do this
So the function would be changed as :
def idCol(cols:Array[String], IdCol: String = FUNCTIONAL_ID): DataFrame = {
df.withColumn(IdCol,concat(col(cols(0)),lit("."),col(cols(1))).dropDuplicates(IdCol)
}
I want to bypass the cols(0), cols(1) and do a generic transformation which takes all elements of array and seperate them by the char "."
You can use concat_ws which has the following definition:
def concat_ws(sep: String, exprs: Column*): Column
You need to convert your column names which are in String to Column type:
import org.apache.spark.sql.functions._
def idCol(cols:Array[String], IdCol: String = FUNCTIONAL_ID): DataFrame = {
val concatCols = cols.map(col(_))
df.withColumn(IdCol, concat_ws(".", concatCols : _*) ).dropDuplicates(IdCol)
}

SCALA: change the separator in Array

I have an Array like this.
scala> var x=Array("a","x,y","b")
x: Array[String] = Array(a, x,y, b)
How do I change the separator comma in array to a :. And finally convert it to string like this.
String = "a:x,y:b"
My aim is to change the comma(separators only) to other separator(say,:), so that i can ignore the comma inside second element i.e, x,y. and later split the string using : as a delimiter
Your question is unclear, but I'll take a shot.
To go from:
val x = Array("a","x,y","b")
to
"a:x,y:b"
You can use mkString:
x.mkString(":")

Storing multiple values from one text field into an array

I have one text field but I want to be able to store the multiple values entered in that text field (eg. 1,2,3,4) stored into an array. So far, all it does is store it all as one element that still has the commas. How can I get rid of the commas and store each value separately?
You can use global split function which works on any Sequence (including String):
If you want it to be separated by commas only:
let array = split("x,y,z") { $0 == "," }
If you'd want to separate by either commas or spaces:
let array = split("x, y z") { contains(", ", $0) }
You can use the string method componentsSeparatedByString(separator: String) -> [String]
For example:
let example = "1,2,3,4"
let elements = textfieldValue.componentsSeparatedByString(",") // elements is an array with Strings.
Just try below :-
NSArray *valueArr=[[yourTextfield stringValue] componentsSeparatedByString:#","];

Resources