How to iterate on map while removing items? - haxe

I am new to haxe and I need to remove items while iterating on a dictionary of elements. Is this possible in Haxe?

Yes, it's possible.
var map:Map<Int, String> = [100 => 'a', 101 => 'b', 102 => 'c'];
trace(map); // {100 => a, 101 => b, 102 => c}
for (v in map.keys()){
if (v == 101) map.remove(v);
}
trace(map); // {100 => a, 102 => c}
You can play with the example at https://try.haxe.org/#AE894

You can remove while looping over the keys of the map.
trace("Remove every 2nd key");
for(k in myMap.keys())
{
if(k % 2 == 0)
myMap.remove(k);
}
See my example here: https://try.haxe.org/#d3525

Related

groovy map populate with default element

Is there more Groovish way of adding an element to map of lists and initialize default list if not exists?
Or in other words what would be a Groovish way to code the below:
def mylist = [1,2,3,4]
def mymap = [:]
for (num in mylist){
if (num % 2 == 0){
pairity = "even"
} else {
pairity = "odd"
}
if (mymap.containsKey(pairity)){
println("Adding to Even")
mymap[pairity].add(num)
}
else {
println("adding to Odd")
mymap[pairity] = [num]
}
}
print(mymap.toString())
// adding to Odd
// adding to Odd
// Adding to Even
// Adding to Even
// [odd:[1, 3], even:[2, 4]]
You can use withDefault on a map to have automatically generate a value for a missing key on access.
[1,2,3,4].inject([:].withDefault{[]}){ m, i -> m[ i%2==0 ? 'odd' : 'even' ] << i; m }
// => [even:[1, 3], odd:[2, 4]]
You can simply groupby:
def mymap = mylist.groupBy { it % 2 == 0 ? 'even' : 'odd' }
That is effectively using the closure to partition the list on the condition.

How to check if two arrays of strings contain the same values (including duplicates)

I have 2 arrays which both containing strings, for example:
a = ['a', 'b', 'a']
b = ['b', 'a', 'a']
I have found that I can use lodash with:
_.isEmpty(_.xor(a,b))
to make sure they both equal.
However this method seems to fail if I have duplicated values in the arrays, for example:
a = ['a', 'b', 'a']
b = ['b', 'a']
the above method will return true for this case (it will print they are equal) although I have 2 'a' in a array and only 1 in b.
Any elegant ways to perform this comparison?
function isEqual(a, b) {
return [...new Set(a.concat(b)] // Get an array of unique elements of both arrays
.filter(t =>
// Filter on those elements whose count in both arrays is different
a.filter(at=>at===t).length !== b.filter(bt=>bt===t).length
)
.length === 0
}
console.log(['a','b'], ['b','a','a'], isEqual(['a','b'], ['b','a','a']))
console.log(['a','b','a'], ['b','a','a'], isEqual(['a','b','a'], ['b','a','a']))
I propose the following if you don't want to sort the array. You take the one array and remove each item from the other. If an item cannot be removed at any time or the array remains with any items in the end, they are not equal.
var a = ['a', 'b', 'a']
var b = ['b', 'a', 'a']
function areEqual(a, b) {
var flag = true;
b.forEach((letter) => {
let i = a.indexOf(letter);
if(i == -1) { flag = false; }
else a.splice(i, 1);
});
if(flag && a.length == 0) { return true; }
else { return false; }
}
console.log(areEqual(a,b));

copy contents of a list to a Dictionary<int, string>

I am pretty new to C# and stuck with a problem with collections. I have a dictionaty with some values say: [(5, "abc"), (6, "def")]. I call a method and get a List like: {"mno", "pqr"}. Now I want to update the value of the dictionary with contents of the list. The problem is the key of the map may start from any number, say from 5. But the starting index of the new list will always be 0 as usual, the length of both the list and the map being same...so I can't so: map[i] = list[i], because they won't match. Can someone please tell me how to replace the contents of the dictionary with that of the list? Please please!!!
Simple For Loop
for (int index = 0; index < map.Count; index++)
{
map[map.ElementAt(index).Key] = list[index];
}
Using Linq
var result = map.Zip(list, (m, l) => new { Key = m.Key, Value = l })
.ToDictionary(p => p.Key, p => p.Value);
Here's a method using LINQ that will create a new Dictionary with the same keys as the old dictionary, but values coming from the list:
map = map.Keys
.OrderBy(k => k)
.Zip(list, (k, v) => new KeyValuePair<int, string>(k, v))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
If you need to update the original Dictionary instead of creating a new one, this will do it:
foreach (var kvp in map.Keys
.OrderBy(k => k)
.Zip(list, (k, v) => new KeyValuePair<int, string>(k, v)))
map[kvp.Key] = kvp.Value;

Groovy: the simplest way to detect duplicate, non-consecutive values in a list

I know that in Groovy,
if
list = [1,2,3,1]
when
list.unique()
with return
[1,2,3]
But if I want to detect duplicate value for duplicate, non-consecutive items in a list. How can I do this?
detect([1,2,3,1]) => true
detect([1,2,3,2]) => true
detect([1,1,2,3]) => false
detect([1,2,2,3,3]) => false
detect([1,2,3,4]) => false
Thanks.
Edit:
add these two cases
detect([1,2,2,1]) => true
detect([1,2,1,1]) => true
true means any non-consecutive, duplicate occur.
This should do it:
List list = ["a", "b", "c", "a", "d", "c", "a"]
and
list.countBy{it}.grep{it.value > 1}.collect{it.key}
In case you need to obtain duplicate elements:
def nonUniqueElements = {list ->
list.findAll{a -> list.findAll{b -> b == a}.size() > 1}.unique()
}
assert nonUniqueElements(['a', 'b', 'b', 'c', 'd', 'c']) == ['b', 'c']
To determine whether a collection contains non-unique items (your first two examples), you can do something like this:
def a = [1, 2, 3, 1]
boolean nonUnique = a.clone().unique().size() != a.size()
(Note that unique() modifies the list).
Meanwhile, Collection.unique() seems to do what you asked as far as 'grouping' items (your last three examples).
Edit: unique() works properly regardless of whether the collection is sorted.
You should be able to metaClass list and add your own detect method as below:
List.metaClass.detect = {
def rslt = delegate.inject([]){ ret, elem ->
ret << (ret && ret.last() != elem ? elem : !ret ? elem : 'Dup')
}
return (!rslt.contains('Dup') && rslt != rslt.unique(false))
}
assert [1,2,3,1].detect() == true //Non-consecutive Dups 1
assert [1,2,3,2].detect() == true //Non-consecutive Dups 2
assert [1,1,2,3].detect() == false //Consecutive Dups 1
assert [1,2,2,3,3].detect() == false //Consecutive Dups 2 and 3
assert [1,2,3,4].detect() == false //Unique no dups
To know if it has duplicates:
stringList.size() == stringList.toSet().size() // if true, it has no duplicates
To know which values are duplicated, you can do something like this:
class ListUtils {
static List<String> getDuplicates(List<String> completeList) {
List<String> duplicates = []
Set<String> nonDuplicates = new HashSet<>()
for (String string in completeList) {
boolean addded = nonDuplicates.add(string)
if (!addded) {
duplicates << string
}
}
return duplicates
}
}
And here its Spock test case:
import spock.lang.Specification
class ListUtilsSpec extends Specification {
def "getDuplicates"() {
when:
List<String> duplicates = ListUtils.getDuplicates(["a", "b", "c", "a"])
then:
duplicates == ["a"]
}
}

In Groovy, how do I add up the values for a certain property in a map?

I have the following map:
def map = [];
map.add([ item: "Shampoo", count: 5 ])
map.add([ item: "Soap", count: 3 ])
I would like to get the sum of all the count properties in the map. In C# using LINQ, it would be something like:
map.Sum(x => x.count)
How do I do the same in Groovy?
Assuming you have a list like so:
List list = [ [item: "foo", count: 5],
[item: "bar", count: 3] ]
Then there are multiple ways of doing it. The most readable is probably
int a = list.count.sum()
Or you could use the Closure form of sum on the whole list
int b = list.sum { it.count }
Or you could even use a more complex route such as inject
int c = list.count.inject { tot, ele -> tot + ele } // Groovy 2.0
// c = list.count.inject( 0 ) { tot, ele -> tot + ele } // Groovy < 2.0
All of these give the same result.
assert ( a == b ) && ( b == c ) && ( c == 8 )
I would use the first one.
You want to use the collect operator. I checked the following code with groovysh:
list1 = []
total = 0
list1[0] = [item: "foo", count: 5]
list1[1] = [item: "bar", count: 3]
list1.collect{ total += it.count }
println "total = ${total}"
First of all, you're confusing map and list syntax in your example. Anyhow, Groovy injects a .sum(closure) method to all collections.
Example:
[[a:1,b:2], [a:5,b:4]].sum { it.a }
===> 6

Resources