LINQ: check whether two list are the same - linq

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;

Related

Sorting Dictionaries containing more complex values in Swift

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.

Getting wrong answer when trying to get k subsets from Array in ActionScript

I'm working on a Texas Holdem game and i need to generate all possible k subsets from an Array of cards (represented as numbers in this example). This is how it looks so far:
public function getKSubsetsFromArray(arr:Array, k:int):Array {
var data:Array = new Array();
var result:Array = new Array();
combinations(arr, data, 0, arr.length - 1, 0, k, result, 0);
return result;
}
public function combinations(arr:Array, data:Array, start:int, end:int, index:int, r:int, resultArray:Array, resultIndex:int):int {
if (index == r) {
trace(resultIndex, data);
resultArray[resultIndex] = data;
return ++resultIndex;
}
for (var i:int = start; i<=end && end-i+1 >= r-index; i++) {
data[index] = arr[i];
resultIndex = combinations(arr, data, i + 1, end, index + 1, r, resultArray, resultIndex);
}
return resultIndex;
}
I am new to Actionscript, my idea is to have a function that takes an array of number and a parameter k, and returns an Array of arrays each of size k. However once i test the functions I get an array containing only the last combination nCk times. For example:
var testArray:Array = new Array(1, 2, 3, 4, 5);
trace(getKSubsetsFromArray(testArray, 3));
Returns:
0 1,2,3
1 1,2,4
2 1,2,5
3 1,3,4
4 1,3,5
5 1,4,5
6 2,3,4
7 2,3,5
8 2,4,5
9 3,4,5
The function output is
3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5,3,4,5
Of course it should print an array containing all the combinations listed before but it only prints the last one the right amount of times.
Thank your for your help.
The reason for the error is that when you are making array of arrays you are actually using the reference of the same array (data) so when the last combination is executed the contains of data array become 3,4,5 and each of index of resultArray points to data array so it prints out same values.
Solution :-
if (index == r) {
trace(resultIndex, data);
var result = new Array();
copy(result,data)
resultArray[resultIndex] = result;
return ++resultIndex;
}
Note :-
The above is pseudo code as i am not familiar with actionscript but you can implement copy function that copies values of data into result in actionscript syntax.

How would you find the initial letter with the most occurrences using recursion?

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.

Order reversed in Aggregate LINQ query

I think the result should contain [1,1,2,2,3,3] but it contains [3,3,2,2,1,1]. Why is the list being reversed?
var sequence = new int[] { 1, 2, 3 };
var result = sequence.Aggregate(
Enumerable.Empty<int>(),
(acc, s) => Enumerable.Repeat(s, 2).Concat(acc));
Thanks
For every item in the sequence, you are concatenating the repetition to the beginning of the accumulated sequence. Swap the order so you are concatenating to the end.
(acc, s) => acc.Concat(Enumerable.Repeat(s, 2))
On a side note, it would be easier (and more efficient) to do this to get that sequence instead.
var result =
from s in sequence
from x in Enumerable.Repeat(s, 2)
select x;
Simpler way to achieve by using SelectMany:
var sequence = new int[] { 1, 2, 3 };
var result = sequence.SelectMany(i => new[] {i, i}).ToArray();

Linq - return index of collection using conditional logic

I have a collection
List<int> periods = new List<int>();
periods.Add(0);
periods.Add(30);
periods.Add(60);
periods.Add(90);
periods.Add(120);
periods.Add(180);
var overDueDays = 31;
I have a variable over due days. When the vale is between 0 to 29 then I want to return the index of 0. When between 30 - 59 I want to return index 1. The periods list is from db so its not hard coded and values can be different from what are here. What is the best way to to it using LINQ in one statement.
It's not really what Linq is designed for, but (assuming that the range is not fixed) you could do the following to get the index
List<int> periods = new List<int>();
periods.Add(0);
periods.Add(30);
periods.Add(60);
periods.Add(90);
periods.Add(120);
periods.Add(180);
var overDueDays = 31;
var result = periods.IndexOf(periods.First(n => overDueDays < n)) - 1;
You can use .TakeWhile():
int periodIndex = periods.TakeWhile(p => p <= overDueDays).Count() - 1;
how about this ?
var qPeriods = periods.Where(v => v <= overDueDays)
.Select((result, i) => new { index = i })
.Last();
Assuming that periods is sorted, you can use the following approach:
var result = periods.Skip(1)
.Select((o, i) => new { Index = i, Value = o })
.FirstOrDefault(o => overDueDays < o.Value);
if (result != null)
{
Console.WriteLine(result.Index);
}
else
{
Console.WriteLine("Matching range not found!");
}
The first value is skipped since we're interested in comparing with the upper value of the range. By skipping it, the indices fall into place without the need to subtract 1. FirstOrDefault is used in case overDueDays doesn't fall between any of the available ranges.

Resources