How to convert a String into HashMap? [duplicate] - collections

This question already has answers here:
How to convert String into Hashmap in java
(8 answers)
Closed 2 years ago.
I have receive string
String message = "Value{A=10,B=20,C=30,D=700-2-1, Bourke STREET, SOUTH 2/28 QUEEN ST,E=40,F=50}";
Map<Object, Object> = {
A = 10 ,
B = 20
C = 30
D = 700-2-1, Bourke STREET, SOUTH 100/28 QUEEN ST
E = 40
F = 50
}
I am looking for a generic approach.
Where
Need All values of A,B,C ....
The order of A,B,C,D,E and F will change
Only D may contain single or multiple commas(,) in its value or no comma

I am thinking String.split(). We first want to split the part of the message inside the curly braces at commas, then at equal signs. However, not at every comma, obviously. Only at commas that go right before a new key letter and an equal sign. In code:
String message
= "Value{A=10,B=20,C=30,"D=700-2-1, Bourke STREET, SOUTH 2/28 QUEEN ST,E=40,F=50}";
String contents = message.replaceFirst("^Value\\{(.*)\\}$", "$1");
String[] pairs = contents.split(",(?=[ABCDEF]=)");
Map<String, String> m = Arrays.stream(pairs)
.map(p -> p.split("=", 2))
.collect(Collectors.toMap(a -> a[0], a -> a[1]));
m.forEach((k, v) -> System.out.println(k + " -> " + v));
Output is:
A -> 10
B -> 20
C -> 30
D -> 700-2-1, Bourke STREET, SOUTH 2/28 QUEEN ST
E -> 40
F -> 50
(?=[ABCDEF]=) in the second regular expression is a positive lookahead. It makes sure that we only match the comma if it is followed by one of those letters and en equal sign. If letters can be other than ABCDEF, you may want to use \w for a word character instead of [ABCDEF].
We don’t necessarily need a stream operation, but you had tagged your question java-stream, so I thought you would like to see one.
The stream operation is not guaranteed to give you a HashMap. Even if you observe that it does (which it did on Java 11 in my case), it may not on the next Java version or even with different input. For the majority of cases this should be no concern. If you have a specific reason for needing to be sure, check what you got and convert if it wasn’t a HashMap:
if (! m.getClass().equals(HashMap.class)) {
m = new HashMap<>(m);
}

This code will work for above scenario :
public static void main(String... args) {
String message = "Value{A=10,B=20,C=30,D=700-2-1, Bourke STREET, SOUTH 2/28 QUEEN ST,E=40,F=50}";
//remove value and curly braces
message = message.substring(6,message.length()-1);
//split by comma followed by capital letter
String[] values= message.split("(?<=,)(?=[A-Z])");
//split and collect to map
Map<String, String> map = Arrays.asList(values).stream()
.map(x-> x.lastIndexOf(",")>-1?x.substring(0, x.lastIndexOf(",")):x)
.map(x-> x.split("="))
.collect(Collectors.toMap(x -> x[0], x-> x[1]));
//print map
System.out.println(map);
}

Related

How to take user input and insert it into an array?

New to Julia, trying to simply ask the user to choose 5 numbers and put it into an array and print the array. My output only says pick 5 numbers with "nothing" followed underneath. I cant seem to figure out why it wont read my inputs.
function ask()
lst = []
i = 0
println("pick 5 numbers to add to a list")
while i < 5
choice = readline
choice = push!(lst, choice);
i += 1
end
end
println(ask())
You were assigning function reference to list elements rather than calling the function.
This should be:
function ask()
lst = String[]
i = 0
println("pick 5 numbers to add to a list")
while i < 5
choice = readline()
choice = push!(lst, choice);
i += 1
end
lst
end
If you want numbers rather than Strings the last line could be parse.(Int, lst) or you could add this conversion near readline
Note that if you do not plan to introduce some error checking etc. this all code could be simply written as:
println("pick 5 numbers to add to a list")
lst = [parse(Int, readline()) for _ in 1:5]

Searching in database with scrambled words in SQLite

I am wondering if its possible to search in the database with the given scrambled words.
I have a mobs table in database and it holds the name of the monster names
If given monster name is A Golden Dregon or A Golden Dfigon or A Gelden Dragon I want it to find A Golden Dragon or with the matches that close to it from database. Usually one or two letters at max is given like this as scrambled.
Is that possible with just SQL queries? Or should I build the query by parsing the given monster name?
I am using LUA for the code side.
I have come to know this search type as a fuzzy search. I mainly program in JS and use fuse.js all the time for this kind of problem.
Fuzzy Searches are based on the Levenshtein algorithm that rate the distance of two strings. When you have this distance value you can sort or drop elements from a list based on the score.
I found the algorithm in lua here.
function levenshtein(s, t)
local s, t = tostring(s), tostring(t)
if type(s) == 'string' and type(t) == 'string' then
local m, n, d = #s, #t, {}
for i = 0, m do d[i] = { [0] = i } end
for j = 1, n do d[0][j] = j end
for i = 1, m do
for j = 1, n do
local cost = s:sub(i,i) == t:sub(j,j) and 0 or 1
d[i][j] = math.min(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cost)
end
end
return d[m][n]
end
end
As explained in the site you compare two strings like so and get a score based on the distance of them, then sort or drop the items being search based on the scores given. As this is CPU expensive I would suggest caching or use a memoize function to store common mistakes.
levenshtein('referrer', 'referrer') -- zero distance
>>> 0
levenshtein('referrer', 'referer') -- distance of one character
>>> 1
levenshtein('random', 'strings') -- random big distance
>>> 6
Got a simple version of it working in lua here I must say lua is an easy language to pick up and start coding with.
local monsters = {'A Golden Dragon', 'Goblins', 'Bunny', 'Dragoon'}
function levenshtein(s, t)
local s, t = tostring(s), tostring(t)
if type(s) == 'string' and type(t) == 'string' then
local m, n, d = #s, #t, {}
for i = 0, m do d[i] = { [0] = i } end
for j = 1, n do d[0][j] = j end
for i = 1, m do
for j = 1, n do
local cost = s:sub(i,i) == t:sub(j,j) and 0 or 1
d[i][j] = math.min(d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1]+cost)
end
end
return d[m][n]
end
end
--Fuzzy Search Returns the Best Match in a list
function fuzzySearch(list, searchText)
local bestMatch = nil;
local lowestScore = nil;
for i = 1, #list do
local score = levenshtein(list[i], searchText)
if lowestScore == nil or score < lowestScore then
bestMatch = list[i]
lowestScore = score
end
end
return bestMatch
end
print ( fuzzySearch(monsters, 'golen dragggon') )
print ( fuzzySearch(monsters, 'A Golden Dfigon') )
print ( fuzzySearch(monsters, 'A Gelden Dragon') )
print ( fuzzySearch(monsters, 'Dragooon') ) --should be Dragoon
print ( fuzzySearch(monsters, 'Funny') ) --should be Bunny
print ( fuzzySearch(monsters, 'Gob') ) --should be Goblins
Output
A Golden Dragon
A Golden Dragon
A Golden Dragon
Dragoon
Bunny
Goblins
For SQL
You can try to do this same algorithm in T-SQL as talked about here.
In SQLlite there is an extension called editdist3 which also uses this algorithm the docs are here.
I would be hard to compensate for all the different one and two letter scrambled combinations, but you could create a lua table of common misspellings of "A Golden Dragon" check if it is in the table. I have never used lua before but here is my best try at some sample code:
local mob_name = "A Golden Dregon"--you could do something like, input("Enter mob name:")
local scrambled_dragon_names = {"A Golden Dregon", "A Golden Dfigon", "A Gelden Dragon"}
for _,v in pairs(scrambled_dragon_names) do
if v == mob_name then
mob_name = "A Golden Dragon"
break
end
end
I really hope I have helped!
P.S. If you have anymore questions go ahead and comment and I will try to answer ASAP.
You will have to parse the given monster name to some extent, by making assumptions about how badly it is misspelled. For example, if the user supplied the name
b fulden gorgon
There is no way in hell you can get to "A Golden Dragon". However, if you assume that the user will always get the first and last letters of every word correctly, then you could parse the words in the given name to get the first and last letters of each word, which would give you
"A", "G" "n", "D" "n"
Then you could use the LIKE operator in your query, like so:
SELECT * FROM mobs WHERE monster_name LIKE 'A G%n D%n';
The main point here is what assumptions you make about the misspelling. The closer you can narrow it down, the better your query results will be.

Pattern Matching SML?

Can someone please explain the: "description of g"? How can f1 takes unit and returns an int & the rest i'm confused about too!!
(* Description of g:
* g takes f1: unit -> int, f2: string -> int and p: pattern, and returns
* an int. f1 and f2 are used to specify what number to be returned for
* each Wildcard and Variable in p respectively. The return value is the
* sum of all those numbers for all the patterns wrapped in p.
*)
datatype pattern = Wildcard
| Variable of string
| UnitP
| ConstP of int
| TupleP of pattern list
| ConstructorP of string * pattern
datatype valu = Const of int
| Unit
| Tuple of valu list
| Constructor of string * valu
fun g f1 f2 p =
let
val r = g f1 f2
in
case p of
Wildcard => f1 ()
| Variable x => f2 x
| TupleP ps => List.foldl (fn (p,i) => (r p) + i) 0 ps
| ConstructorP (_,p) => r p
| _ => 0
end
Wildcard matches everything and produces the empty list of bindings.
Variable s matches any value v and produces the one-element list holding (s,v).
UnitP matches only Unit and produces the empty list of bindings.
ConstP 17 matches only Const 17 and produces the empty list of bindings (and similarly for other integers).
TupleP ps matches a value of the form Tuple vs if ps and vs have the same length and for all i, the i-th element of ps matches the i-th element of vs. The list of bindings produced is all the lists from the nested pattern matches appended together.
ConstructorP(s1,p) matches Constructor(s2,v) if s1 and s2 are the same string (you can compare them with =) and p matches v. The list of bindings produced is the list from the nested pattern match. We call the strings s1 and s2 the constructor name.
Nothing else matches.
Can someone please explain the: "description of g"? How can f1 takes unit and returns an int & the rest i'm confused about too!!
The function g has type (unit → int) → (string → int) → pattern → int, so it takes three (curried) parameters of which two are functions and one is a pattern.
The parameters f1 and f2 must either be deterministic functions that always return the same constant, or functions with side-effects that can return an arbitrary integer / string, respectively, determined by external sources.
Since the comment speaks of "what number to be returned for each Wildcard and Variable", it sounds more likely that the f1 should return different numbers at different times (and I'm not sure what number refers to in the case of f2!). One definition might be this:
local
val counter = ref 0
in
fun uniqueInt () = !counter before counter := !counter + 1
fun uniqueString () = "s" ^ Int.toString (uniqueInt ())
end
Although this is just a guess. This definition only works up to Int.maxInt.
The comment describes g's return value as
[...] the sum of all those numbers for all the patterns wrapped in p.
Since the numbers are not ascribed any meaning, it doesn't seem like g serves any practical purpose but to compare the output of an arbitrarily given set of f1 and f2 against an arbitrary test that isn't given.
Catch-all patterns are often bad:
...
| _ => 0
Nothing else matches.
The reason is that if you extend pattern with additional types of patterns, the compiler will not notify you of a missing pattern in the function g; the catch-all will erroneously imply meaning for cases that are possibly yet undefined.

How to convert a group of Hexadecimal to Decimal (Visual Studio )

I want to retrieve like in Pic2, the values in Decimal. ( hardcoded for visual understanding)
This is the codes to convert Hex to Dec for 16 bit:
string H;
int D;
H = txtHex.Text;
D = Convert.ToInt16(H, 16);
txtDec.Text = Convert.ToString(D);
however it doesn't work for a whole group
So the hex you are looking at does not refer to a decimal number. If it did refer to a single number that number would be far too large to store in any integral type. It might actually be too large to store in floating point types.
That hex you are looking at represents the binary data of a file. Each set of two characters represents one byte (because 16^2 = 2^8).
Take each pair of hex characters and convert it to a value between 0 and 255. You can accomplish this easily by converting each character to its numerical value. In case you don't have a complete understanding of what hex is, here's a map.
'0' = 0
'1' = 1
'2' = 2
'3' = 3
'4' = 4
'5' = 5
'6' = 6
'7' = 7
'8' = 8
'9' = 9
'A' = 10
'B' = 11
'C' = 12
'D' = 13
'E' = 14
'F' = 15
If the character on the left evaluates to n and the character on the right evaluates to m then the decimal value of the hex pair is (n x 16) + m.
You can use this method to get your values between 0 and 255. You then need to store each value in an unsigned char (this is a C/C++/ObjC term - I have no idea what the C# or VBA equivalent is, sorry). You then concatenate these unsigned char's to create the binary of the file. It is very important that you use an 8 bit type to store these values. You should not store these values in 16 bit integers, as you do above, or you will get corrupted data.
I don't know what you're meant to output in your program but this is how you get the data. If you provide a little more information I can probably help you use this binary.
You will need to split the contents into separate hex-number pairs ("B9", "D1" and so on). Then you can convert each into their "byte" value and add it to a result list.
Something like this, although you may need to adjust the "Split" (now it uses single spaces, returns, newlines and tabs as separator):
var byteList = new List<byte>();
foreach(var bytestring in txtHex.Text.Split(new[] {' ', '\r', '\n', '\t'},
StringSplitOptions.RemoveEmptyEntries))
{
byteList.Add(Convert.ToByte(bytestring, 16));
}
byte[] bytes = byteList.ToArray(); // further processing usually needs a byte-array instead of a List<byte>
What you then do with those "bytes" is up to you.

How do I convert a list of strings into a URL query string in functional style?

This question is about functional programming, not about how to build URL query strings. The language I'm working in is Objective-C but that's also not especially relevant.
I have a starting data structure that's an array of strings. Each odd element is the parameter name, each even one is the value eg, [firstname, bob, lastname, smith, gender, male].
Is there an idiomatic FP approach to converting this list into a URL query string (eg. "firstname=bob&lastname=smith&gender=male")?
I'm thinking something along the lines of 'partition using a mod 2 predicate' to give me 2 lists of keys and values respectively, then zipWith a function that url escapes the keys and values and joins them with '='. That will give me a list of 'a=b' strings. Then I should be able to do a fold-left to insert the '&' symbols.
I think I may have just answered my own question! Sweet! Posting it anyway in case someone more familiar with FP idioms wants to comment.
Thanks!
Here's a more-or-less direct translation of your English into C#:
var list = new[]{"firstname", "bob", "lastname", "smith", "gender", "male"};
string.Join("&",
list.Where((k, i) => i % 2 == 0)
.Zip(list.Where((v, i) => i % 2 == 1),
(k, v) => k + "=" + v));
This would be more or less it, in Haskell using only standard prelude functions:
queryStr paramList = joinAmp $ map (uncurry joinEq) $ group2 paramList
where joinEq x y = x ++ "=" ++ y
joinAmp = foldr1 (\x y -> x ++ "&" ++ y)
group2 [] = []
group2 (x:y:xs) = (x, y) : group2 xs
qStr = queryStr ["firstname", "bob", "lastname", "smith", "gender", "male"]
Check whether your environment has a string joining function. E.g., in Python you can do "&".join(lst) for the joinAmp function, above. I've used a right-fold because of the way Haskell implements string concatenation.
String o;
for (i=0; i< -1 + size(strings); i=i+2) {
if (i==0) {
o += "?";
} else {
o += "&";
};
o+= strings[i]+"="+ strings[i+1];
}
print o;

Resources