This question already has answers here:
Is it safe to remove selected keys from map within a range loop?
(4 answers)
Closed 3 years ago.
I wrote some code which does this, and it is working fine, but when reviewing the code I realize what I did might not have worked in other languages.
To give a contrived example:
dict := map[string]string{ "a": "1", "b": "2" }
for key, val := range dict {
fmt.Println(val)
delete(dict, "b")
}
This prints "1" and "2", and when I inspect dict afterward it is { "a": "1" } only.
So, I get the impression that it is safe to do this, but I'm wondering why?
Does range dict create a copy internally?
As always, the spec is the definitive answer. Under "For statements with range clause", item 3 (emphasis mine):
The iteration order over maps is not specified and is not guaranteed to be the same from one iteration to the next. If a map entry that has not yet been reached is removed during iteration, the corresponding iteration value will not be produced. If a map entry is created during iteration, that entry may be produced during the iteration or may be skipped. The choice may vary for each entry created and from one iteration to the next. If the map is nil, the number of iterations is 0.
Related
I have a data series that contains various names of the same organizations. I want harmonize these names into a given standard using a mapping dictionary. I am currently using a nested for loop to iterate through each series element and if it is within the dictionary's values, I update the series value with the dictionary key.
# For example, corporation_series is:
0 'Corp1'
1 'Corp-1'
2 'Corp 1'
3 'Corp2'
4 'Corp--2'
dtype: object
# Dictionary is:
mapping_dict = {
'Corporation_1': ['Corp1', 'Corp-1', 'Corp 1'],
'Corporation_2': ['Corp2', 'Corp--2'],
}
# I use this logic to replace the values in the series
for index, value in corporation_series.items():
for key, list in mapping_dict.items():
if value in list:
corporation_series = corporation_series.replace(value, key)
So, if the series has a value of 'Corp1', and it exists in the dictionary's values, the logic replaces it with the corresponding key of corporations. However, it is an extremely expensive method. Could someone recommend me a better way of doing this operation? Much appreciated.
I found a solution by using python's .map function. In order to use .map, I had to invert my dictionary:
# Inverted Dict:
mapping_dict = {
'Corp1': ['Corporation_1'],
'Corp-1': ['Corporation_1'],
'Corp 1': ['Corporation_1'],
'Corp2': ['Corporation_2'],
'Corp--2':['Corporation_2'],
}
# use .map
corporation_series.map(newdict)
Instead of 5 minutes of processing, took around 5s. While this is works, I sure there are better solutions out there. Any suggestions would be most welcome.
I wanted to learn more about for loops, as far as I know there are different types?
For instance,
for i = 1, 5 do
print("hello")
end
^ I know about this one, it's going to print hello 5 times, but there are others like the one below which I do not understand, specifically the index bit (does that mean it is number 1?) and what is the ipairs for
for index, 5 in ipairs(x) do
print("hello")
end
If there are any other types please let me know, I want to learn all of them and if you can provide any further reading I'd be more than greatful to check them out
As you can read in the Lua reference manual
3.3.5 For Statement
The for statement has two forms: one numerical and one generic.
The numerical for loop repeats a block of code while a control
variable runs through an arithmetic progression. It has the following
syntax:
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
Example:
for i = 1, 3 do
print(i)
end
Will output
1
2
3
You seem familiar with that one. Read the reference manual section for more details.
The generic for statement works over functions, called iterators. On
each iteration, the iterator function is called to produce a new
value, stopping when this new value is nil. The generic for loop has
the following syntax:
stat ::= for namelist in explist do block end namelist ::= Name {‘,’
Name}
Example:
local myTable = {"a", "b", "c"}
for i, v in ipairs(myTable) do
print(i, v)
end
Will ouput
1 a
2 b
3 c
ipairs is one of those iterator functions mentioned:
Returns three values (an iterator function, the table t, and 0) so
that the construction
for i,v in ipairs(t) do body end will iterate over the key–value pairs (1,t[1]), (2,t[2]), ..., up to the first nil value.
Read more about ipairs and pairs here:
https://www.lua.org/manual/5.3/manual.html#pdf-pairs
https://www.lua.org/manual/5.3/manual.html#pdf-ipairs
Of course you can implement your own iterator functions!
Make sure you also read:
Programming in Lua: 7 Iterators and the Generic for
Yes, It will print hello 5 times
According to this answer on Difference between pairs, ipairs, and next?
ipairs does the exact same thing as pairs, but with a slight twist to it.
ipairs runs through the table, until it finds a nil value, or a value that is non-existent, if that makes sense. So, if you ran the script I showed you for pairs, but just replaced pairs with ipairs, it would do the exact same thing
This question already has answers here:
Meaning of underscore (blank identifier) in Go [duplicate]
(5 answers)
Closed 6 years ago.
Here is specific example
func main(){
m := make(map[string]int)
m["k1"] = 7
_, prs := m["k2"]
fmt.Println(prs)
}
What does "_" signifies here?
Rest is clear to me.
The _ means that you don't care about this particular return value.
Accessing a map index yield 2 values :
The value a that index, or the zero-value of the value type
A boolean indicating whether or not a value was at that index
In your case, prs will be the boolean.
This pattern is often used like this :
if _, found := m[key]; !found {
// Do something here to handle the fact that there is nothing at the index `key`
}
Map being a special type in Go, the second value is optional, so if you don't care about whether or not there is something in the map you don't have to check for it.
See dokumentation. Your statement:
_, prs := m["k2"]
is doing two things at the same time. A) Checking whether a key/value is present in the map and B) is retrieves the value. "prs" is a boolean indicating whether the value was present for the key "k2" or not.
Thus, if you only want to check if a key/value is present in the map and do not care to use the value, you can use the "_" to ignore the value and only use the "prs" boolean.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
What is the correct way to remove an item from a slice in GO?
Also, what is the correct way to reinitialize a slice i.e. completely empty it but still keep it?
I believe you are misunderstanding the nature of a slice. A slice is like an ArrayList in Java. It is backed by a regular array and grows/shrinks on demand. Operations on a slice have the same performance characteristic as those you would expect on an ArrayList.
Your question(s) would make more sense if slices were the LinkedList equivalent. For that, look up Package list.
Nevertheless, here's how to do this. Most comes directly from SliceTricks, but I think it's good practice on SO to not refer to links and provide the answer right here.
Way to remove an item from a slice
This is something that you can do in any programming language, in O(1) time, if you don't care about order. If you care about order, this is not going to work.
The idea is to overwrite the item you want to remove with the last item in the slice, then reduce the size of the slice by one.
arr := []string{ "allo", "hello", "bye", "chao" }
// delete "bye"
deleteIdx := 2
lastIdx := len(arr) - 1
// arr = { "allo", "hello", "chao", "chao" }
arr[deleteIdx] = arr[lastIdx]
// arr = { "allo", "hello", "chao" } ... "chao"
arr = arr[:lastIdx - 1]
You can do that in a single step (SliceTricks):
arr[deleteIdx], arr = arr[len(arr)-1], arr[:len(arr) - 1]
However, like mentionned in the SliceTricks article, some type of values will not be garbage collected if you don't nil them, as the backing array behind the slice still holds a reference to them. The solution is to nil them while doing the operation.
arr[len(arr)-1], arr[deleteIdx], arr = nil, arr[len(arr)-1], arr[:len(arr)-1]
// ^ Setting the deleted index to nil ^
This is all, of course, if you don't care about preserving order. If you do care, you will need to copy everything after deleteIdx starting over deleteIdx, which is O(n). If you find yourself doing this, think if there isn't a better datastructure for your needs.
// Copy everything from [deleteIdx+1 .. n) onto [deleteIdx .. )
copy(arr[deleteIdx:], arr[deleteIdx+1:])
// arr[n - 1] and arr[n] have the same value (n = len(arr) - 1)
arr[len(arr)-1] = nil
// re-slice to reference only the n-1 elements
arr = arr[:len(arr)-1]
Way to reinitialize a slice i.e. completely empty it but keep it
You can reinitialize a slice by re-slicing all its items out
// Keep everything from [0 .. 0), which means keep nothing
arr = arr[:0]
But there's a problem in doing this : as stated above, the backing array of the slice will still reference to the original items that were in the slice. What you should do instead is create a new slice and let this one be garbage collected.
The answer is manyfold:
You must realize that there is no slice without backing array and if you talk about a slice you always have to think about the backing array too. Musing about this a bit leads to...
The second part of the question "reinitialize a slice i.e. completely empty it but still keep it" is very unclear. Do not think about slices in this way. a = a[:0] reslices a to zero length while keeping the backing array.
For everything else: Have a look at the "official" Slice Tricks https://code.google.com/p/go-wiki/wiki/SliceTricks
I have some critical error with the hash's size function. This is acting irationnal.
Here is my hash :
"questionnaires"=>{"1"=>{"6"=>"8", "7"=>"12", "5"=>"19"}}
#questions=evt["questionnaires"]["1"] # not really "1", that's an id but don't matter here
#questions.each do |(key,question)| # should be "6"=>"8", then "7"=>"12", ect ...
temp = question.size
And results are 1 , 2 , 2. So it is bugging, i am testing with size cause sometimes i get an array like this :
so, i don't know why
"6"=>"8".size == 1, "7"=>"12".size == 2 and "5"=>"19".size == 2.
And with this array
"questionnaires"=>{"3"=>{"8"=>{"16"=>"16", "18"=>"18"}}}
results are correct. Size = 2, like expected.
Any ideas ?
When you have (key,question) parameters like you do, they get filled in parallel assignment as it iterates through the hash. So, for example, the first iteration key is "6" and question is "8". The second iteration, key is "7" and question is "12".
And you are asking question.size. But since question is just a String, question.size returns the length of the string. The first iteration through, the question id "8" is 1 character long. The second iteration, the question id "12" is 2 characters long. That's where the numbers you are getting are coming from.