Can anyone explain the following LINQ example code from microsoft...
I am having trouble understanding the (digit, index) part of the lambda expression:
public void Linq5()
{
string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
var shortDigits = digits.Where((digit, index) => digit.Length < index);
Console.WriteLine("Short digits:");
foreach (var d in shortDigits)
{
Console.WriteLine("The word {0} is shorter than its value.", d);
}
}
I am having trouble understanding the (digit, index) part of the lambda expression:
There are two overloads to Where. One takes a predicate mapping instances of the sequence type to bool, and the other takes a predicate mapping pairs of (instance of the sequence type, index in the sequence) to bool. This is so you can say things like
sequence.Where((x, index) => index % 2 == 0 && x.Length > 5))
That is: give me all the items in the sequence with even index and length more than 5.
In this example:
digits.Where((digit, index) => digit.Length < index);
we are saying: give me all the items in the sequence with item length less than its position in the sequence, i.e., all the digits whose length is shorter than the value it represents.
Those are the lambda expression's parameters.
The compiler will infer their types based on the delegate that the lambda is being used as.
In this case, that's Func<T, int, bool> from the Where() overload.
The lambda expression is a shortcut to writing the psedocode:
bool FunctionWithNoName(string digit, int index)
{
return (digit.Length < index);
}
Related
I'm trying to use zipWithIndex to index of the first negative value in my List by creating a method function that takes a List[Int] and will return an Int or an option[Int] for me to use. First, I created the list and the function with zipWithIndex but I keep getting type mismatch error:
val list = List(-2,-1,2,3,4)
def getNegativeIndex(xs: List[Int]): Int = {
for ((x, count) <- xs.zipWithIndex if x < 0) yield(count)
}
and this is the error I keep getting:
type mismatch;
found : List[Int] => Int
required: Int
My aim is to index off the first negative value of the List "list"
i.e my result should be getNegativeIndex(list) == 0 using the list I provided since the 1st element -2 is at index 0
pls, what do I need to add to the above function or remove to achieve my goal
In order for getNegativeIndex(list) to return a single integer and your desired value you need to only return the headOption of the list that your for-comprehension generates.
The current for-comprehension is equivalent to
xs.zipWithIndex.filter(_._1 < 0).map(_._2). So you can either do this
xs.zipWithIndex.filter(_._1 < 0).map(_._2).headOption
Or add the headOption to your comprehension like this
(
for ((x, count) <- xs.zipWithIndex if x < 0) yield(count)
).headOption
The result will be the same, i.e. the function returns the first index of a negative number in the list or None if all are non-negative. You could instead use .head to get an integer directly but be aware that it will throw an exception if the list doesn't contain any negative number or is empty.
The key-sorting according to values of a dictionary with simple Doubles or Ints works perfectly fine according to the example provided here....
But what about more complex dictionary-structures ?
I have a dictionary with dictionary-values that each consist of an array of Double-Tuples. (pretty complex, I know....).
And I would like to sort the dictionary-values according to the sum of the Second-Tuple-Array. (i.e. all second-tuple elements form an array and this array is summed-up; then sort the array-sums according to the smallest value). But all that still without loosing information on the dictionary-key. The result of the asked method shall return an array of keys according to the sorted result of "second-tuple-summed-up-array-results).
Here my "poor" trial for this problem :
I tried to sort the keys according to the values of the first-Tuple of the array-of-Tuples with the following Playground example (see below). But it does not perform yet....
This works for basic types:
extension Dictionary {
func keysSortedByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return sorted(self) {
let (lk, lv) = $0
let (rk, rv) = $1
return isOrderedBefore(lv, rv)
}.map { (k,v) in k }
}
}
let dict = ["a":2, "c":1, "b":3]
dict.keysSortedByValue(<) // result array of keys: ["c", "a", "b"]
dict.keysSortedByValue(>) // result array of keys: ["b", "a", "c"]
But in my more complex case, it doesn't work:
var criteria_array1 = [(Double, Double)]()
var criteria_array2 = [Double]()
var criteria_dict1 = [String:[(Double, Double)]]()
var criteria_dict2 = [String:[Double]]()
// Random creation of two dictionaries with a complex value-structure...
// Dictionary1: keys = Strings, values = array of Double-Tuples
// Dictionary2: keys = Strings, values = array of Doubles
for n in 1...5 {
let currentTopoString: String = "topo_\(n)"
for t in 0...14 {
let a: Double = Double(arc4random_uniform(1000))
let b: Double = Double(Double(arc4random_uniform(1000))/1000)
criteria_array1 += [(a, b)]
criteria_array2 += [b]
}
criteria_dict1[currentTopoString] = criteria_array1
criteria_dict2[currentTopoString] = criteria_array2
criteria_array1.removeAll()
criteria_array2.removeAll()
}
// the two following instruction generate compiler errors....
// why ???????????
// How could a complex dictionary-value-structure be applied to a sortingMethod ??
criteria_dict1.keysSortedByFirstTupleValue(>)
criteria_dict2.keysSortedByFirstTupleValue(>)
This is a question of implementing the isOrderedBefore function appropriately. Just passing in > is not going to cut it (even assuming there was an implementation of > for arrays of tuples, it almost certainly wouldn't do the comparison-of-summation you are looking for).
If I understand your goal correctly, you want to sort the keys based on the value of the sum of one of the tuple entries in an array of tuples?
So something like this:
criteria_dict1.keysSortedByValue { lhs, rhs in
// if you actually want to sort by sum of first element in tuple,
// change next.1 to next.0
let left_sum = reduce(lhs, 0) { total, next in total + next.1 }
let right_sum = reduce(rhs, 0) { total, next in total + next.1 }
return left_sum > right_sum
}
This is quite inefficient, since you're summing the array for every comparison – in practice you may want to memoize it, or maybe rethink the problem in terms of a different data structure if you do this a lot.
Given a sentence that is spread over a linked list where each item in the list is a word, for example:
Hello -> Everybody -> How -> Are -> You -> Feeling -> |
Given that this list is sorted, eg:
Are -> Everybody -> Feeling -> Hello -> How -> You -> |
How would you write the recursion that will find the initial letter that appears the most in the sentence (in this example the letter H from Hello & How) ?
Edit: I have update the code to recursion version.
In order to run it you call
GetMostLetterRecursion(rootNode , '0', 0, '0', 0)
The code itself look like this:
public char GetMostLetterRecursion(LinkedListNode<String> node, char currentChar, int currentCount, char maxChar, int maxCount)
{
if (node == null) return maxChar;
char c = node.Value[0];
if (c == currentChar)
{
return GetMostLetterRecursion(node.Next, currentChar, currentCount++, maxChar, maxCount);
}
if(currentCount > maxCount)
{
return GetMostLetterRecursion(node.Next, c, 1, currentChar, currentCount);
}
return GetMostLetterRecursion(node.Next, c, 1, maxChar, maxCount);
}
Solution 1
Loop over the words, keeping a tally of how many words start with each letter. Return the most popular letter according to the tally (easy if you used a priority queue for the tally).
This takes O(n) time (the number of words) and O(26) memory (the number of letters in alphabet).
Solution 2
Sort the words alphabetically. Loop over the words. Keep a record of the current letter and its frequency, as well as the most popular letter so far and its frequency. At the end of the loop, that's the most popular letter over the whole list.
This takes O(n log n) time and O(1) memory.
Keep an array to store the count of occurrences and Go through the linked list once to count it. Finally loop through the array to find the highest one.
Rough sketch in C:
int count[26]={0};
While ( head->next != NULL)
{
count[head->word[0] - 'A']++; // Assuming 'word' is string in each node
head = head->next;
}
max = count[0];
for (i=0;i<26;i++)
{
if(max<a[i])
max = a[i];
}
You can modify it to use recursion and handle lower case letters.
Here is a pure recursive implementation in Python. I haven't tested it, but it should work modulo typos or syntax errors. I used a Dictionary to store counts, so it will work with Unicode words too. The problem is split into two functions: one to count the occurrences of each letter, and another to find the maximum recursively.
# returns a dictionary where dict[letter] contains the count of letter
def count_first_letters(words):
def count_first_letters_rec(words, count_so_far):
if len(words) == 0:
return count_so_far
first_letter = words[0][0]
# could use defaultdict but this is an exercise :)
try:
count_so_far[first_letter] += 1
except KeyError:
count_so_far[first_letter] = 1
# recursive call
return count_first_letters_rec(words[1:], count_so_far)
return count_first_letters(words, {})
# takes a list of (item, count) pairs and returns the item with largest count.
def argmax(item_count_pairs):
def argmax_rec(item_count_pairs, max_so_far, argmax_so_far):
if len(item_count_pairs) == 0:
return argmax_so_far
item, count = item_count_pairs[0]
if count > max_so_far:
max_so_far = count
argmax_so_far = item
# recursive call
return argmax_rec(item_count_pairs[1:], max_so_far, argmax_so_far)
return argmax_rec(item_count_pairs, 0, None)
def most_common_first_letter(words);
counts = count_first_letters(words)
# this returns a dictionary, but we need to convert to
# a list of (key, value) tuples because recursively iterating
# over a dictionary is not so easy
kvpairs = counts.items()
# counts.iteritems() for Python 2
return argmax(kvpairs)
I have an array with the length of 26 (as English letters, so index 1 is for 'a' and 2 for 'b' and so on. ). Each time a letter occurs, I increment it's value in the array. if the value becomes more than max amount, then I update the max and take that letter as most occurred one.then I call the method for the next node.
This is the code in Java:
import java.util.LinkedList;
public class MostOccurance {
char mostOccured;
int maxOccurance;
LinkedList<String> list= new LinkedList<String>();
int[] letters= new int[26];
public void start(){
findMostOccuredChar( 0, '0', 0);
}
public char findMostOccuredChar ( int node, char most, int max){
if(node>=list.size())
return most;
String string=list.get(node);
if (string.charAt(0)== most)
{max++;
letters[Character.getNumericValue(most)-10]++;
}
else{
letters[Character.getNumericValue(most)-10]++;
if (letters[Character.getNumericValue(most)-10]++>max){
max=letters[Character.getNumericValue(most)-10];
most=string.charAt(0);
}
}
findMostOccuredChar( node++, most, max);
return most;
}
}
of course, you have to add each word to your link list. I didn't do that, because I was just showing an example.
when passing EqualityComparer as last parameter to Linq Join method it is not using Equals method of it, it for some reason is using GetHashCode to compare items.
Is it possible to make it use Equals instead?
var ss = new string[] { "aa", "bb", "cc" };
var zz = new string[] { "aa", "zz", "cc" };
var res = ss
.Join(zz,
o => o,
i => i,
(i, o) => i + o,
new GenericEqualityComparer<String>((x,y) => x == y))
.ToList();
When an IEqualityComparer<T> compares to objects, it first compares their hashcodes. Only if they are equal the Equals method is used to refine the comparison. So in your case it should at least hit Equals twice.
To demonstrate what an EqualityComparer does I made a little code snippet in Linqpad:
void Main()
{
var ss = new string[] { "aa1", "bb1", "cc1" };
var zz = new string[] { "aa2", "aa3", "zz2", "cc2" };
var res = ss.Join(zz, o => o, i => i, (i, o) => i + o,
new SubstringComparer()).ToList();
}
public class SubstringComparer : IEqualityComparer<string>
{
public bool Equals(string left, string right)
{
string.Format("{0} - {1}", left, right).Dump();
return left.Substring(0,2) == right.Substring(0,2);
}
public int GetHashCode(string value)
{
value.Dump();
return value.Substring(0,2).GetHashCode();
}
}
So strings are equal if their first two characters are equal. The output is:
aa2
aa3
aa2 - aa3
zz2
cc2
aa1
aa2 - aa1
bb1
cc1
cc2 - cc1
And the resulting list:
aa1aa2
aa1aa3
cc1cc2
You see that first the second list is compared (I'm not sure why, by the way, maybe the hashcodes are cached) and then the pairs.
So when your GenericEqualityComparer never hits Equals it somehow always generates a unique hashcode, which I think should be a bug. If it not always uses Equals, here is the explanation. And if you want a comparer to always use Equals you should make it always return an identical hashcode (which is inefficient, of course).
https://stackoverflow.com/a/3719802/136967
has a very good explanation. Basically, comparisons are done using Equals() but GetHashCode() is used by the Linq code when doing the processing and if not implemented correctly it will give strange answers.
hth,
Alan.
This should be easy.
I want to check whether two list are the same in that they contain all the same elements or not, orders not important.
Duplicated elements are considered equal, i.e.e, new[]{1,2,2} is the same with new[]{2,1}
var same = list1.Except(list2).Count() == 0 &&
list2.Except(list1).Count() == 0;
Edit: This was written before the OP added that { 1, 2, 2 } equals { 1, 1, 2 } (regarding handling of duplicate entries).
This will work as long as the elements are comparable for order.
bool equal = list1.OrderBy(x => x).SequenceEqual(list2.OrderBy(x => x));
The SetEquals of HashSet is best suited for checking whether two sets are equal as defined in this question
string stringA = "1,2,2";
string stringB = "2,1";
HashSet<string> setA = new HashSet<string>((stringA.Trim()).Split(',').Select(t => t.Trim()));
HashSet<string> setB = new HashSet<string>((stringB.Trim()).Split(',').Select(t => t.Trim()));
bool isSetsEqual = setA.SetEquals(setB);
REFERENCE:
Check whether two comma separated strings are equal (for Content set)
You need to get the intersection of the two lists:
bool areIntersected = t1.Intersect(t2).Count() > 0;
In response to you're modified question:
bool areSameIntersection = t1.Except(t2).Count() == 0 && t2.Except(t1).Count() == 0;
If the count of list1 elements in list2 equals the count of list2 elements in list1, then the lists both contain the same number of elements, are both subsets of each other - in other words, they both contain the same elements.
if (list1.Count(l => list2.Contains(l)) == list2.Count(l => list1.Contains(l)))
return true;
else
return false;