Ordered iteration in map string 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

Related

Why can't I use removeAll on a list of objects?

I am trying to create an app that let's you type in what you want to eat and drink. It calculates all of that and then when you press the print button, I want it to count how often each item's in the list and give it back like this:
"9x Juice /n
5x Steaks /n
4x Salads"
The drinks and foods are objects in the new class Edibles:
class Edibles(val name: String, val price: Double):Serializable {
}
I track all of the objects in the MutableList order and can access the different members of the list and their attributes, but when I try to removeAll duplicates in my list, android studio complains and I don't know how to fix it.
My try to calculate how many members are in the list order:
var totalOrder = ""
for(i in order){
var number = order.count {it == order[0]}
totalOrder = totalOrder + "$number" + "x" + order[0].name + "\n"
order.removeAll(order[0])
}
The problem as far as I saw so far is, that Edibles doesn't have the interface Collection and when I try to implement that, it wants me to override a bunch of functions where I don't know what to do with it...
If anyone has an explanation or even a fix or an idea on how to do it differently, I would be very grateful
removeAll is meant to take a list or a predicate, not a single element. If you convert your element to a predicate checking for equality, it will remove all elements equal to that one.
order.removeAll { it == order[0] }
However, you'll also need to remember rule number one of iteration: Never delete while iterating. So what you really want to do is accumulate all of the "deletion" candidates into a list and then delete them after-the-fact.
In fact, what you're doing here can be done without mutating the list at all, using a built-in list combinator called groupBy.
var totalOrder = ""
for (entry in order.groupBy { it }) {
val item = entry.key
val count = entry.value.size
totalOrder += "${count}x${item.name}\n"
}
You're not allowed to mutate a collection while iterating it in a for loop anyway. One way to remove duplicates would be to create a temporary MutableSet and compare each item to it in a removeAll operation. removeAll takes a lambda predicate that is called on each item and the Boolean you return from the predicate. When you call add on a MutableSet, it returns a Boolean to tell you if the item already was in the set, so you can remove duplicates with the following.
Assuming you just want to compare names of items to determine if they are duplicates, you can create a MutableSet<String>.
with (mutableSetOf<String>()) {
order.removeAll { add(it.name) }
}

How to see if map keys contain certain strings?

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.

Scala string manipulation

I have the following Scala code :
val res = for {
i <- 0 to 3
j <- 0 to 3
if (similarity(z(i),z(j)) < threshold) && (i<=j)
} yield z(j)
z here represents Array[String] and similarity(z(i),z(j)) calculates similarity between two strings.
This problems works like that similarity is calculated between 1st string and all the other strings and then similarity is calculated between 2nd string and all other strings except for first and then similarity for 3rd string and so on.
My requirement is that if 1st string matches with 3rd, 4th and 8th string, then
all these 3 strings shouldn't participate in loops further and loop should jump to 2nd string, then 5th string, 6th string and so on.
I am stuck at this step and don't know how to proceed further.
I am presuming that your intent is to keep the first String of two similar Strings (eg. if 1st String is too similar to 3rd, 4th, and 8th Strings, keep only the 1st String [out of these similar strings]).
I have a couple of ways to do this. They both work, in a sense, in reverse: for each String, if it is too similar to any later Strings, then that current String is filtered out (not the later Strings). If you first reverse the input data before applying this process, you will find that the desired outcome is produced (although in the first solution below the resulting list is itself reversed - so you can just reverse it again, if order is important):
1st way (likely easier to understand):
def filterStrings(z: Array[String]) = {
val revz = z.reverse
val filtered = for {
i <- 0 to revz.length if !revz.drop(i+1).exists(zz => similarity(zz, revz(i)) < threshold)
} yield revz(i)
filtered.reverse // re-reverses output if order is important
}
The 'drop' call is to ensure that each String is only checked against later Strings.
2nd option (fully functional, but harder to follow):
val filtered = z.reverse.foldLeft((List.empty[String],z.reverse)) { case ((acc, zt), zz) =>
(if (zt.tail.exists(tt => similarity(tt, zz) < threshold)) acc else zz :: acc, zt.tail)
}._1
I'll try to explain what is going on here (in case you - or any readers - aren't use to following folds):
This uses a fold over the reversed input data, starting from the empty String (to accumulate results) and the (reverse of the) remaining input data (to compare against - I labeled it zt for "z-tail").
The fold then cycles through the data, checking each entry against the tail of the remaining data (so it doesn't get compared to itself or any earlier entry)
If there is a match, just the existing accumulator (labelled acc) will be allowed through, otherwise, add the current entry (zz) to the accumulator. This updated accumulator is paired with the tail of the "remaining" Strings (zt.tail), to ensure a reducing set to compare against.
Finally, we end up with a pair of lists: the required remaining Strings, and an empty list (no Strings left to compare against), so we take the first of these as our result.
If I understand correctly, you want to loop through the elements of the array, comparing each element to later elements, and removing ones that are too similar as you go.
You can't (easily) do this within a simple loop. You'd need to keep track of which items had been filtered out, which would require another array of booleans, which you update and test against as you go. It's not a bad approach and is efficient, but it's not pretty or functional.
So you need to use a recursive function, and this kind of thing is best done using an immutable data structure, so let's stick to List.
def removeSimilar(xs: List[String]): List[String] = xs match {
case Nil => Nil
case y :: ys => y :: removeSimilar(ys filter {x => similarity(y, x) < threshold})
}
It's a simple-recursive function. Not much to explain: if xs is empty, it returns the empty list, else it adds the head of the list to the function applied to the filtered tail.

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

I Need to Make a HashMap Print out words in order of value

This is my code so far, what am I doing wrong? I need to create a HashMap of <Integer,ArrayList<String>> which will map each word of the test data keyed to the length of the word. Then, display the test String and iterate through the keys and display the words ordered by length. I am not entirely sure what I am doing wrong. Should I use an iterator as opposed to a for-each loop, or would that not make much of a difference?
This is my code thus far
HashMap<Integer,String>map = new HashMap<Integer,String>();
// adds values
map.put(2, "The");
map.put(8, "Superbowl");
Instead of an HashMap, you should use a SortedMap: "A Map that further provides a total ordering on its keys" (JDK 1.7 API doc). A TreeMap would do.
A sorted map will return its keys in sorted order. Since your keys are Integer (hence Comparable), their natural ordering is used.
To list the words by increasing length:
SortedMap<Integer, List<String>> wordsByLength; // filled somewhere
// Iterates over entries in increasing key order
Set<Map.Entry<Integer, List<String>> entries = wordsByLength.entrySet();
for ( Map.Entry<Integer, List<String>> entry : entries ) {
int length = entry.getKey();
List<String> words = entry.getValue();
// do what you need to do
}
Since order is not gauranteed in a HashMap you would need to pull out the keys and sort them before using the sorted key list to loop through the values like so:
Map<Integer,String>map = new HashMap<Integer,String>();
map.put(2, "The");
map.put(8, "Superbowl");
List<Integer> keyList = new ArrayList<Integer>(map.keySet());
Collections.sort(keyList);
for (Integer key : keyList) {
System.out.println(map.get(key));
}
However in your use case where words are the same length you would end up overwriting previous entries in the Map which would not be what you want. A better solution would be to store the words in a List and sort them using a Comparator that compared String lengths like this:
List<String> words = new ArrayList<String>();
// Loop through adding words if they don't already exist in the List
// sort the List by word length
Collections.sort(words, new Comparator<String>() {
public int compare(String s1, String s2) {
return Integer.valueOf(s1.length()).compareTo(s2.length());
}
});
//Now loop through sorted List and print words
for (String word : words) {
System.out.println(word);
}

Resources