How to see if map keys contain certain strings? - string

Suppose I have a slice of strings like:
fruits := {"apple", "orange", "banana"}
and a map like
box:= map[string]int{
"chicken": 1,
"drinks": 4,
"apples": 42,
}
What is the most efficient way to check whether the box contains any apple, orange or banana?
Notice that here we seek not exact match but a key that CONTAINS certain strings. So simple key search does not work here.
I know I can extract keys from the map:
keys := make([]string)
for k := range box {
keys = append(keys, k)
}
And then iterate over both slices to search among the keys:
for _, f := range fruits {
for _, k in keys {
if strings.Contains(k, f) {
fmt.Println("Fruit found!")
}
}
But that refutes the advantage of using map instead of slice for string searchs. So is there better way to do so?

You don't need to extract the keys:
for _, f := range fruits {
for k,fruit := range box {
if strings.Contains(k, f) {
fmt.Printf("Fruit found!: %s",fruit)
}
}
}
If you only need to check if key exists, you can write for k := range box
Since this is a contains search, there is no easy way to do it. If it was a begins with search, there are other data structures you might want to look at, such as a trie, or prefix-tree. There isn't standard library support for those.

Related

In-place modification, insertion or removal in the same function for hash maps in Rust

Say I have a hash map m: HashMap<K, V>, a key k: K and a value v: V, and would like to do the following:
If m does not contain a value at index k, insert v at index k.
If m contains a value w at index k, apply a function fn combine(x: V, y: V) -> Option<V> to v and w, and:
If the result is None, remove the entry at index k from m.
If the result is Some(u), replace the value at index k by u.
Is there a way to do this "in-place", without calling functions that access, modify or remove the value at k multiple times?
I would also like to avoid copying data, so ideally one shouldn't need to clone v to feed the clones into insert and combine separately.
I could rewrite combine to use (mutable) references (or inline it), but the wish of not copying data still remains.
Digging deeper into the Entry documentation, I noticed that the variants of the Entry enum offer functions to modify, remove or insert entries in-place.
After taking std::collections::hash_map::Entry into scope, one could do the following:
match m.entry(k) {
Entry::Occupied(mut oe) => {
let w = oe.get_mut();
match combine(v, w) {
Some(u) => { *w = u; },
None => { oe.remove_entry(); },
}
},
Entry::Vacant(ve) => { ve.insert(v); },
}
(Here is a PoC in the Rust playground.)
This, however, requires combine to take a (mutable) reference as its second argument (which is fine in my case).
I managed to do it in one access, one write and one key-deletion in total in the worst case. The last key-deletion should not be necessary, but I'm not certain it can be done. I gave it my best so far. I hope this helps!
Okay, so I think we want to use the Entry API.
The full method list for Entry is here.
I think we'd do it in the following order:
If m contains a value w at index k: (two more steps)
Or insert v at index k.
This can be done by using .and_modify and then .or_insert. Something like this:
let map = // ... Initialize the map
// Do stuff to it
// ...
// Our important bit:
let mut delete_entry = false;
map.entry(k)
.and_modify(|w| { // If the entry exists, we modify it
let u = combine(v, w);
match u {
Some(y) => *w = y;
None => delete_entry = true;
}
}
)
.or_insert(v); // If it doesn't, we insert v
if delete_entry {
map.remove(k);
}
I don't think there's a way to do all three things without that last map.remove access, so this is my best attempt for now.

sort list of maps in grovvy

Hi I have a list of maps in groovy like
def v=[[val1:'FP'],[val1:'LP'],[val1:'MP'],[val1:'MP'],[val1:'LP'],[val1:'FP']]
I wanted to sort based on the following order FP,MP,LP
I tried doing
v.sort{x,y->
x.val1 <=> y.val1
}
which prints [[val1:FP], [val1:FP], [val1:LP], [val1:LP], [val1:MP], [val1:MP]] which is sorted alphabetically, but I need it to be sorted in the following format
FP,MP,LP
An alternative: Whenever I am dealing with a fixed, ordered list of strings I immediately think of using enums instead:
enum PValue { FP, MP, LP }
Now we have an ordered set of constants that readily converts to and from string values. So sorting looks as simple as this:
v.sort { x, y -> PValue[x.val1] <=> PValue[y.val1] }
EDIT: Or even simpler:
v.sort { PValue[it.val1] }
As has been said int the comments, you need to define a preferred order, and then sort based on that... so with your list of maps:
def v=[[val1:'FP'],[val1:'LP'],[val1:'MP'],[val1:'MP'],[val1:'LP'],[val1:'FP']]
And a preferred order of results:
def preferredOrder = ['FP', 'MP', 'LP']
You can then sort based on the values index into this preferred order:
v.sort(false) { preferredOrder.indexOf(it.val1) }
Or, if you want unknown elements (ie: [val1:'ZP']) to go at the end of the sorted list, then you an do:
v.sort(false) { preferredOrder.indexOf(it.val1) + 1 ?: it.val1 }
So if they are not found (index -1) then they are compared on their String name
This question is similar to this one btw, which has more options in the answer

What are the possible consequences of using unsafe conversion from []byte to string in go?

The preferred way of converting []byte to string is this:
var b []byte
// fill b
s := string(b)
In this code byte slice is copied, which can be a problem in situations where performance is important.
When performance is critical, one can consider performing the unsafe conversion:
var b []byte
// fill b
s := *(*string)(unsafe.Pointer(&b))
My question is: what can go wrong when using the unsafe conversion? I known that string should be immutable and if we change b, s will also be changed. And still: so what? Is it all bad that can happen?
Modifying something that the language spec guarantees to be immutable is an act of treason.
Since the spec guarantees that strings are immutable, compilers are allowed to generate code that caches their values and does other optimization based on this. You can't change values of strings in any normal way, and if you resort to dirty ways (like package unsafe) to still do it, you lose all the guarantees provided by the spec, and by continuing to use the modified strings, you may bump into "bugs" and unexpected things randomly.
For example if you use a string as a key in a map and you change the string after you put it into the map, you might not be able to find the associated value in the map using either the original or the modified value of the string (this is implementation dependent).
To demonstrate this, see this example:
m := map[string]int{}
b := []byte("hi")
s := *(*string)(unsafe.Pointer(&b))
m[s] = 999
fmt.Println("Before:", m)
b[0] = 'b'
fmt.Println("After:", m)
fmt.Println("But it's there:", m[s], m["bi"])
for i := 0; i < 1000; i++ {
m[strconv.Itoa(i)] = i
}
fmt.Println("Now it's GONE:", m[s], m["bi"])
for k, v := range m {
if k == "bi" {
fmt.Println("But still there, just in a different bucket: ", k, v)
}
}
Output (try it on the Go Playground):
Before: map[hi:999]
After: map[bi:<nil>]
But it's there: 999 999
Now it's GONE: 0 0
But still there, just in a different bucket: bi 999
At first, we just see some weird result: simple Println() is not able to find its value. It sees something (key is found), but value is displayed as nil which is not even a valid value for the value type int (zero value for int is 0).
If we grow the map to be big (we add 1000 elements), internal data structure of the map gets restructured. After this, we're not even able to find our value by explicitly asking for it with the appropriate key. It is still in the map as iterating over all its key-value pairs we find it, but since hash code changes as the value of the string changes, most likely it is searched for in a different bucket than where it is (or where it should be).
Also note that code using package unsafe may work as you expect it now, but the same code might work completely differently (meaning it may break) with a future (or old) version of Go as "packages that import unsafe may be non-portable and are not protected by the Go 1 compatibility guidelines".
Also you may run into unexpected errors as the modified string might be used in different ways. Someone might just copy the string header, someone may copy its content. See this example:
b := []byte{'h', 'i'}
s := *(*string)(unsafe.Pointer(&b))
s2 := s // Copy string header
s3 := string([]byte(s)) // New string header but same content
fmt.Println(s, s2, s3)
b[0] = 'b'
fmt.Println(s == s2)
fmt.Println(s == s3)
We created 2 new local variables s2 and s3 using s, s2 initialized by copying the string header of s, and s3 is initialized with a new string value (new string header) but with the same content. Now if you modify the original s, you would expect in a correct program that comparing the new strings to the original you would get the same result be it either true or false (based on if values were cached, but should be the same).
But the output is (try it on the Go Playground):
hi hi hi
true
false

How to search Lua table values

I have a project that calls for a relational database like structure in an environment where an actual database isn't possible. The language is restricted to Lua, which is far from being my strongest language. I've got a table of tables with a structure like this:
table={
m:r={
x=1
y=1
displayName="Red"
}
m:y={
x=1
y=2
displayName="Yellow"
}
}
Building, storing and retrieving the table is straightforward enough. Where I'm running into issues is searching it. For the sake of clarity, if I could use SQL I'd do this:
SELECT * FROM table WHERE displayName="Red"
Is there a Lua function that will let me search this way?
The straightforward way is to iterate through all elements and find one that matches your criteria:
local t={
r={
x=1,
y=1,
displayName="Red",
},
y={
x=1,
y=2,
displayName="Yellow",
},
}
for key, value in pairs(t) do
if value.displayName == 'Red' then
print(key)
end
end
This should print 'r'.
This may be quite slow on large tables. To speed up this process, you may keep track of the references in a hash that will provide much faster access. Something like this may work:
local cache = {}
local function findValue(key)
if cache[key] == nil then
local value
-- do a linear search iterating through table elements searching for 'key'
-- store the result if found
cache[key] = value
end
return cache[key]
end
If the elements in the table change their values, you'll need to invalidate the cache when the values are updated or removed.
There are no built-in functions for searching tables. There are many ways to go about it which vary in complexity and efficiency.
local t = {
r={displayname="Red", name="Ruby", age=15, x=4, y=10},
y={displayname="Blue", name="Trey", age=22, x=3, y=2},
t={displayname="Red", name="Jack", age=20, x=2, y=3},
h={displayname="Red", name="Tim", age=25, x=2, y=33},
v={displayname="Blue", name="Bonny", age=10, x=2, y=0}
}
In Programming in Lua they recommend building a reverse table for efficient look ups.
revDisplayName = {}
for k,v in pairs(t) do
if revDisplayName[v.displayname] then
table.insert(revDisplayName[v.displayname], k)
else
revDisplayName[v] = {k}
end
end
Then you can match display names easily
for _, rowname in pairs(revDisplayName["Red"]) do
print(t[rowname].x, t[rowname].y)
end
There is code for creating SQL-like queries in Lua, on Lua tables, in Beginning Lua Programming if you want to build complex queries.
If you just want to search through a few records for matches, you can abstract the searching using an iterator in Lua
function allmatching(tbl, kvs)
return function(t, key)
repeat
key, row = next(t, key)
if key == nil then
return
end
for k, v in pairs(kvs) do
if row[k] ~= v then
row = nil
break
end
end
until row ~= nil
return key, row
end, tbl, nil
end
which you can use like so:
for k, row in allmatching(t, {displayname="Red", x=2}) do
print(k, row.name, row.x, row.y)
end
which prints
h Tim 2 33
t Jack 2 3

Ordered iteration in map string string

In the Go blog, this is how to print the map in order.
http://blog.golang.org/go-maps-in-action
import "sort"
var m map[int]string
var keys []int
for k := range m {
keys = append(keys, k)
}
sort.Ints(keys)
for _, k := range keys {
fmt.Println("Key:", k, "Value:", m[k])
}
but what if I have the string keys like var m map[string]string
I can't figure out how to print out the string in order(not sorted, in order of string creation in map container)
The example is at my playground http://play.golang.org/p/Tt_CyATTA3
as you can see, it keeps printing the jumbled strings, so I tried map integer values to map[string]string but I still could not figure out how to map each elements of map[string]string.
http://play.golang.org/p/WsluZ3o4qd
Well, the blog mentions that iteration order is randomized:
"...When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next"
The solution is kind of trivial, you have a separate slice with the keys ordered as you need:
"...If you require a stable iteration order you must maintain a separate data structure that specifies that order."
So, to work as you expect, create an extra slice with the correct order and the iterate the result and print in that order.
order := []string{"i", "we", "he", ....}
func String(result map[string]string) string {
for _, v := range order {
if present in result print it,
}
... print all the Non-Defined at the end
return stringValue
}
See it running here: http://play.golang.org/p/GsDLXjJ0-E

Resources