I wish to implement a Logic for Compare two List in a single iteration using C# (Un-Sorted List).
For Example:
List<string> listA = new List<string>() {"IOS", "Android", "Windows"};
List<string> listB = new List<string>() {"LINUS", "IOS"};
now I need to compare listB with listA, and I need to trace the missing items in listB like "Android", "Windows" without using C# predefined methods.
Note: Iterate each list only once.
Kindly assist me.
This is most likely one of the most optimized answers you are likely to find:
public static List<T> Except<T>(List<T> a, List<T> b)
{
var hash = new HashSet<T>(b);
var results = new List<T>(a.Count);
foreach (var item in a)
{
if (!hash.Contains(item))
{
results.Add(item);
}
}
return results;
}
Rather than the X x Y iterations you get from comparing lists directly, you get X + Y - Y from iterating the comparison list (when converting to a hash table), and X for iterating over the source list (no additional Y since hash table lookups are constant time).
try this
var objectList3 = listA.Where(o => !listB.Contains(o)).ToList();
I don't know if I got it completly right (please correct me if not), but this could be helpful:
//Remove all elements of b from a
foreach (string item in b)
{
a.Remove(item);
}
// check for all elements of a if they exist in b and store them in c if not
public static List<string> Excepts(List<string> a, List<string> b)
{
List<string> c = new List<string>();
foreach (string s1 in a)
{
bool found = false;
foreach (string s2 in b)
{
if (s1 == s2)
{
found = true;
break;
}
}
if (!found)
c.Add(s1);
}
return c;
}
I'm not very familiar with Java, and I'm a bit unsure of how to translate this from c# into java.
Dictionary<string, int> myDictionary = GetDictionary();
int N = 10;
myDictionary
.OrderByDescending(dictionaryEntry => dictionaryEntry.Value)
.Take(N)
.Select(dictionaryEntry => dictionaryEntry.Key)
.ToList();
Now, I KNOW the dictionary itself isnt being sorted, its just a new IEnumberable, and that's OK.
Thanks!
I'm not a C# guy, I've never worked with it, but if I should take a guess it seems like you are sorting the map by its values in descending order, retrieving the 10 first elements, then converting the keys of those 10 elements into a list.
If the values are known to be distinct, then it's kind of trivial - you just convert to a SortedMap with keys and values exchanged. So I'm assuming that the values are not distinct, i.e. that the same number may appear multiple times.
In that case it's not as trivial, and definitely not as simple as in your C# example. My first thought was to create a sorted set with a custom comparator, where each element in the set is a Map.Entry from your map, where the keys and values are exchanged.
This will actually require quite a bit of code in Java. Heres one attempt:
// Create a SortedSet of the reversed entry set, with a custom comparator for sorting
SortedSet<Map.Entry<Integer, String>> sortedSet = new TreeSet<Map.Entry<Integer, String>>(
new Comparator<Map.Entry<Integer, String>>() {
public int compare(Map.Entry<Integer, String> o1, Map.Entry<Integer, String> o2) {
// sort by key, then by value --> in descending order
int keyCompareResult = -o1.getKey().compareTo(o2.getKey()); // negate --> descending
int valueCompareResult = o1.getValue().compareTo(o2.getValue());
return keyCompareResult == 0 ? valueCompareResult : -keyCompareResult;
}
});
// Add all entries of the map to the sorted set
for (Map.Entry<String, Integer> entry : map.entrySet()) {
Map.Entry<Integer, String> reversedEntry = new AbstractMap.SimpleEntry<Integer, String>(entry.getValue(), entry.getKey());
sortedSet.add(reversedEntry);
}
// Convert the 10 first elements to the resulting list
int N = 10;
List<String> result = new ArrayList<String>(N);
Iterator<Map.Entry<Integer,String>> iterator = sortedSet.iterator();
while (iterator.hasNext() && result.size() < N) {
Map.Entry<Integer, String> entry = iterator.next();
result.add(entry.getValue());
}
I came up with pretty much the same thing as Steinar suggested, if you know of a more LINQ-y/functional way to do it, please add your answer too!
//Convert to List of Map.Entry
ArrayList<Map.Entry<String,Integer>> myArrayList = ArrayList<Map.Entry<String,Integer>>(myHashMap.entrySet());
//Natural order is ascending, so we reverse the comparator to get it Descending.
Collections.sort(myArrayList , Collections.reverseOrder(new EntryComparator()));
//Create list and add Keys
List<String> topNStrings = new ArrayList<String>();
for (int i = 0; i < N && i < myArrayList.size(); i++)
{
topNStrings.add(myArrayList.get(i).getKey());
}
and had a separate little comparator class
private class EntryComparator implements Comparator<Map.Entry<String,Integer>>
{
#Override
public int compare(Map.Entry<String,Integer> x, Map.Entry<String,Integer> y)
{
return compare(x.getValue(), y.getValue());
}
private int compare(Integer a, Integer b)
{
return a < b ? -1
: a > b ? 1
: 0;
}
}
Let us start with an arbitrary HashMap that you have acquired somehow defined by HashMap<String, Integer> map.
We want to sort the values and then get the first N values.
int N = 10;
List<Integer> values = new ArrayList<Integer>( map.values() );
Collections.sort(values);
List<Integer> N_values = values.subList(0, N);
I'm looking on how to sort a list effectively using weighted values.
Each item has an id, name and filepath. Each item also has a list of values which are assigned a percentage, showing how relevant they are to each value.
I need the list to be sorted so that the items which are at the top end of the list are the ones which are the most relevant to the current parameters.
Lets say,
Item One:
A: 50, B: 30, C : 20, D : 10
X : 50, Z :20
Item Two:
A:100, B:0, C:0, D:0
X:0, Z:100
And my parameters are A and Z. Clearly Item Two should be at the top of my list as it's the most relevant item. But how would I go about implementing this?
Bonus: Would be nice to be able to have a slight randomisation as well, I don't want to be served the definitive relevant item each time.
Thanks
Assuming you know your weighting function, you could use Linq to Objects:
var sorted = (from o in myList orderby o.SortingValue select o).ToList();
In this example, SortingValue would be a property on the object that encapsulates the attributes in your question and would implement your algorithm.
Sample algorithm for SortingValue:
You could use a Dictionary to hold relevance percentages
Then, your "current parameters" could be used as keys to the Dictionary to get the relevant weighting:
Dictionary<string, double> weightDictionary = // Load somehow
double SortingValue
{
get {
double sortingValue;
foreach(string currentParameter in currentParameters)
{
sortingValue += weightDictionary[currentParameter];
}
// You could use Math.Random to get a number between say -0.1 and -.1.
// Multiply sortingValue by that random number.
return sortingValue;
}
}
A long time ago I created an extension method just for this purpose. I've just came across the need for it again:
public static IOrderedEnumerable<TSource> OrderByWeight<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, int> weighting) where TKey : IComparable
{
Dictionary<TSource, int> order = new Dictionary<TSource, int>();
foreach (TSource item in source)
{
if (!order.ContainsKey(item)) order.Add(item, weighting(keySelector(item)));
}
return source.OrderBy(s => order[s]);
}
You can use it like this:
var data = dt.Select(g => new
{
Season = g.season,
AverageTemp = g.temp
}).OrderByWeight(a => a.Season, x =>
{
if (x == "WINTER") return 1;
if (x == "SPRING") return 2;
if (x == "SUMMER") return 3;
if (x == "AUTUMN") return 4;
return 99;
});
Source: from my old blog
I am trying to figure out a way to correctly sort a bunch of different arraylists.
I am publishing content articles and every value [0] in an arraylist will relate to every other value [0]. and so on. Each element makes up the collective parts of a complete content item.
Now, the last element, popularity, is the amount of clicks an item has received. How do I
do a sort of the content items based on popularity without mixing up the html for each article?
*EDIT I am limited by the .NET 2.0 Framework at Work*
Below is the code... thanks.
public class MultiDimDictList : Dictionary<string, ArrayList> { }
myDicList.Add("fly", a_fly);
myDicList.Add("img", a_img);
myDicList.Add("bar", a_bar);
myDicList.Add("meter", a_meter);
myDicList.Add("block", a_block);
myDicList.Add("popularity", a_pop);
If you use the following code you can convert your existing dictionary of arraylists into a collection of Dictionaries and thus allowing a simple sort using Linq OrderBy
// Get the shortest arraylist length (they should be equal this is just a paranoia check!)
var count=myDicList.Values.Min(x=>x.Count);
// Get the collection of Keys
var keys=myDicList.Keys;
// Perform the conversion
var result=Enumerable.Range(0,count).Select(i=>keys.Select(k=>new {Key=k,Value=myDicList[k][i]}).ToDictionary(x=>x.Key,x=>x.Value));
var sorted=result.OrderByDescending(x=>x["popularity"]).ToList()
-- EDIT VERSION FOR .NET 2.0
First you need a comparer class
class PopularityComparison : IComparer<Dictionary<string,object>> {
private bool _sortAscending;
public PopularityComparison(bool sortAscending) {
_sortAscending = sortAscending;
}
public int Compare(Dictionary<string, object> x, Dictionary<string, object> y) {
object xValue = x["popularity"];
object yValue = y["popularity"];
// Sort Ascending
if (_sortAscending) {
return Comparer.Default.Compare(xValue, yValue);
} else {
return Comparer.Default.Compare(yValue, xValue);
}
}
}
Then you can use the following code
// Get the shortest arraylist length (they should be equal this is just a paranoia check!)
// Replacement for min
int count = int.MaxValue;
foreach (ArrayList a in myDicList.Values) if (a.Count < count) count = a.Count;
// Get the collection of Keys
Dictionary<string, ArrayList>.KeyCollection keys = myDicList.Keys;
// Perform the conversion
List<Dictionary<string, object>> result = new List<Dictionary<string, object>>(count);
for (int i = 0; i < count; i++) {
Dictionary<string, object> row = new Dictionary<string, object>(keys.Count);
foreach (string key in keys) row.Add(key, myDicList[key][i]);
result.Add(row);
}
And then finally to sort in ascending popularity order
result.Sort(new PopularityComparison(true));
or Descending order
result.Sort(new PopularityComparison(true));
I'd think it would be better to have an object containing your keys as properties, then a single collection with each item you'd have in your array lists.
This way you'd have a single collection sort, which becomes trivial if using Linq.OrderBy().
something like...
public class Article
{
public string Fly{get;set;}
public string Img{get;set;}
// etc.
public float Popularity{get;set;}
}
Then...
List<Article> articles = ... get from somewhere, or convert from your array lists.
List<Article> sorted = articles.OrderBy(a=>a.Popularity).ToList();
Please excuse the napkin code here... I'll update it if you need more detail.
An example using non-linq.
Create an implementation of IComparer.
public class ArticleComparer : IComparer<Article>
{
public bool Accending { get; set; }
public int Compare(Article x, Article y)
{
float result = x.Popularity - y.Popularity;
if (!Accending) { result *= -1; }
if (result == 0) { return 0; }
if (result > 0) return 1;
return -1;
}
}
Then when you go to sort the List, you can do something like the following.
ArticleComparer comparer = new ArticleComparer();
comparer.Accending = false;
articles.Sort(comparer);
This would be much easier if you had a list of article objects, each of which contained properties for fly, img, bar, popularity, etc. But if you really have to store things using this inside-out approach, then the only way you can sort the content items based on popularity is to create another array (or list) to hold the order.
Create a new list and populate it with sequential indexes:
List<int> OrderedByPopularity = new List<int>();
ArrayList popList = myDicList["popularity"];
for (int i = 0; i < popList.Count; ++i)
{
OrderedByPopularity.Add(i);
}
Now you have a list that contains the indexes of the items in the popularity list. Now you can sort:
OrderedByPopularity.Sort((i1, i2) => return popList[i1].CompareTo(popList[i2]););
But that gives you the least popular article first. If you want to reverse the sort so that OrderedByPopularity[0] is the most popular item:
OrderedByPopularity.Sort((i1, i2) => { return popList[i2].CompareTo(popList[i1]);});
Really, though, you should look into restructuring your application. It's much easier to work with objects that have properties rather than trying to maintain parallel arrays of properties.
If you have to do this in .NET 2.0, declare the poplist array at class scope (rather than method scope), and create a comparison method.
ArrayList poplist;
void MyMethod()
{
List<int> OrderedByPopularity = new List<int>();
popList = myDicList["popularity"];
for (int i = 0; i < popList.Count; ++i)
{
OrderedByPopularity.Add(i);
}
OrderedByPopularity.Sort(PopularityComparison);
// ...
}
int PopularityComparison(int i1, int i2)
{
return ((int)popList[i2]).CompareTo((int)popList[i1]);
}
I would like to compare the contents of a couple of collections in my Equals method. I have a Dictionary and an IList. Is there a built-in method to do this?
Edited:
I want to compare two Dictionaries and two ILists, so I think what equality means is clear - if the two dictionaries contain the same keys mapped to the same values, then they're equal.
Enumerable.SequenceEqual
Determines whether two sequences are equal by comparing their elements by using a specified IEqualityComparer(T).
You can't directly compare the list & the dictionary, but you could compare the list of values from the Dictionary with the list
As others have suggested and have noted, SequenceEqual is order-sensitive. To solve that, you can sort the dictionary by key (which is unique, and thus the sort is always stable) and then use SequenceEqual. The following expression checks if two dictionaries are equal regardless of their internal order:
dictionary1.OrderBy(kvp => kvp.Key).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key))
EDIT: As pointed out by Jeppe Stig Nielsen, some object have an IComparer<T> that is incompatible with their IEqualityComparer<T>, yielding incorrect results. When using keys with such an object, you must specify a correct IComparer<T> for those keys. For example, with string keys (which exhibit this issue), you must do the following in order to get correct results:
dictionary1.OrderBy(kvp => kvp.Key, StringComparer.Ordinal).SequenceEqual(dictionary2.OrderBy(kvp => kvp.Key, StringComparer.Ordinal))
In addition to the mentioned SequenceEqual, which
is true if two lists are of equal length and their corresponding
elements compare equal according to a comparer
(which may be the default comparer, i.e. an overriden Equals())
it is worth mentioning that in .Net4 there is SetEquals on ISet objects,
which
ignores the order of elements and any duplicate elements.
So if you want to have a list of objects, but they don't need to be in a specific order, consider that an ISet (like a HashSet) may be the right choice.
Take a look at the Enumerable.SequenceEqual method
var dictionary = new Dictionary<int, string>() {{1, "a"}, {2, "b"}};
var intList = new List<int> {1, 2};
var stringList = new List<string> {"a", "b"};
var test1 = dictionary.Keys.SequenceEqual(intList);
var test2 = dictionary.Values.SequenceEqual(stringList);
This is not directly answering your questions, but both the MS' TestTools and NUnit provide
CollectionAssert.AreEquivalent
which does pretty much what you want.
I didn't know about Enumerable.SequenceEqual method (you learn something every day....), but I was going to suggest using an extension method; something like this:
public static bool IsEqual(this List<int> InternalList, List<int> ExternalList)
{
if (InternalList.Count != ExternalList.Count)
{
return false;
}
else
{
for (int i = 0; i < InternalList.Count; i++)
{
if (InternalList[i] != ExternalList[i])
return false;
}
}
return true;
}
Interestingly enough, after taking 2 seconds to read about SequenceEqual, it looks like Microsoft has built the function I described for you.
.NET Lacks any powerful tools for comparing collections. I've developed a simple solution you can find at the link below:
http://robertbouillon.com/2010/04/29/comparing-collections-in-net/
This will perform an equality comparison regardless of order:
var list1 = new[] { "Bill", "Bob", "Sally" };
var list2 = new[] { "Bob", "Bill", "Sally" };
bool isequal = list1.Compare(list2).IsSame;
This will check to see if items were added / removed:
var list1 = new[] { "Billy", "Bob" };
var list2 = new[] { "Bob", "Sally" };
var diff = list1.Compare(list2);
var onlyinlist1 = diff.Removed; //Billy
var onlyinlist2 = diff.Added; //Sally
var inbothlists = diff.Equal; //Bob
This will see what items in the dictionary changed:
var original = new Dictionary<int, string>() { { 1, "a" }, { 2, "b" } };
var changed = new Dictionary<int, string>() { { 1, "aaa" }, { 2, "b" } };
var diff = original.Compare(changed, (x, y) => x.Value == y.Value, (x, y) => x.Value == y.Value);
foreach (var item in diff.Different)
Console.Write("{0} changed to {1}", item.Key.Value, item.Value.Value);
//Will output: a changed to aaa
To compare collections you can also use LINQ. Enumerable.Intersect returns all pairs that are equal. You can comparse two dictionaries like this:
(dict1.Count == dict2.Count) && dict1.Intersect(dict2).Count() == dict1.Count
The first comparison is needed because dict2 can contain all the keys from dict1 and more.
You can also use think of variations using Enumerable.Except and Enumerable.Union that lead to similar results. But can be used to determine the exact differences between sets.
How about this example:
static void Main()
{
// Create a dictionary and add several elements to it.
var dict = new Dictionary<string, int>();
dict.Add("cat", 2);
dict.Add("dog", 3);
dict.Add("x", 4);
// Create another dictionary.
var dict2 = new Dictionary<string, int>();
dict2.Add("cat", 2);
dict2.Add("dog", 3);
dict2.Add("x", 4);
// Test for equality.
bool equal = false;
if (dict.Count == dict2.Count) // Require equal count.
{
equal = true;
foreach (var pair in dict)
{
int value;
if (dict2.TryGetValue(pair.Key, out value))
{
// Require value be equal.
if (value != pair.Value)
{
equal = false;
break;
}
}
else
{
// Require key be present.
equal = false;
break;
}
}
}
Console.WriteLine(equal);
}
Courtesy : https://www.dotnetperls.com/dictionary-equals
For ordered collections (List, Array) use SequenceEqual
for HashSet use SetEquals
for Dictionary you can do:
namespace System.Collections.Generic {
public static class ExtensionMethods {
public static bool DictionaryEquals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> d1, IReadOnlyDictionary<TKey, TValue> d2) {
if (object.ReferenceEquals(d1, d2)) return true;
if (d2 is null || d1.Count != d2.Count) return false;
foreach (var (d1key, d1value) in d1) {
if (!d2.TryGetValue(d1key, out TValue d2value)) return false;
if (!d1value.Equals(d2value)) return false;
}
return true;
}
}
}
(A more optimized solution will use sorting but that will require IComparable<TValue>)
No, because the framework doesn't know how to compare the contents of your lists.
Have a look at this:
http://blogs.msdn.com/abhinaba/archive/2005/10/11/479537.aspx
public bool CompareStringLists(List<string> list1, List<string> list2)
{
if (list1.Count != list2.Count) return false;
foreach(string item in list1)
{
if (!list2.Contains(item)) return false;
}
return true;
}
There wasn't, isn't and might not be, at least I would believe so. The reason behind is collection equality is probably an user defined behavior.
Elements in collections are not supposed to be in a particular order though they do have an ordering naturally, it's not what the comparing algorithms should rely on. Say you have two collections of:
{1, 2, 3, 4}
{4, 3, 2, 1}
Are they equal or not? You must know but I don't know what's your point of view.
Collections are conceptually unordered by default, until the algorithms provide the sorting rules. The same thing SQL server will bring to your attention is when you trying to do pagination, it requires you to provide sorting rules:
https://learn.microsoft.com/en-US/sql/t-sql/queries/select-order-by-clause-transact-sql?view=sql-server-2017
Yet another two collections:
{1, 2, 3, 4}
{1, 1, 1, 2, 2, 3, 4}
Again, are they equal or not? You tell me ..
Element repeatability of a collection plays its role in different scenarios and some collections like Dictionary<TKey, TValue> don't even allow repeated elements.
I believe these kinds of equality are application defined and the framework therefore did not provide all of the possible implementations.
Well, in general cases Enumerable.SequenceEqual is good enough but it returns false in the following case:
var a = new Dictionary<String, int> { { "2", 2 }, { "1", 1 }, };
var b = new Dictionary<String, int> { { "1", 1 }, { "2", 2 }, };
Debug.Print("{0}", a.SequenceEqual(b)); // false
I read some answers to questions like this(you may google for them) and what I would use, in general:
public static class CollectionExtensions {
public static bool Represents<T>(this IEnumerable<T> first, IEnumerable<T> second) {
if(object.ReferenceEquals(first, second)) {
return true;
}
if(first is IOrderedEnumerable<T> && second is IOrderedEnumerable<T>) {
return Enumerable.SequenceEqual(first, second);
}
if(first is ICollection<T> && second is ICollection<T>) {
if(first.Count()!=second.Count()) {
return false;
}
}
first=first.OrderBy(x => x.GetHashCode());
second=second.OrderBy(x => x.GetHashCode());
return CollectionExtensions.Represents(first, second);
}
}
That means one collection represents the other in their elements including repeated times without taking the original ordering into account. Some notes of the implementation:
GetHashCode() is just for the ordering not for equality; I think it's enough in this case
Count() will not really enumerates the collection and directly fall into the property implementation of ICollection<T>.Count
If the references are equal, it's just Boris
I've made my own compare method. It returns common, missing, and extra values.
private static void Compare<T>(IEnumerable<T> actual, IEnumerable<T> expected, out IList<T> common, out IList<T> missing, out IList<T> extra) {
common = new List<T>();
missing = new List<T>();
extra = new List<T>();
var expected_ = new LinkedList<T>( expected );
foreach (var item in actual) {
if (expected_.Remove( item )) {
common.Add( item );
} else {
extra.Add( item );
}
}
foreach (var item in expected_) {
missing.Add( item );
}
}
Comparing dictionaries' contents:
To compare two Dictionary<K, V> objects, we can assume that the keys are unique for every value, thus if two sets of keys are equal, then the two dictionaries' contents are equal.
Dictionary<K, V> dictionaryA, dictionaryB;
bool areDictionaryContentsEqual = new HashSet<K>(dictionaryA.Keys).SetEquals(dictionaryB.Keys);
Comparing collections' contents:
To compare two ICollection<T> objects, we need to check:
If they are of the same length.
If every T value that appears in the first collection appears an equal number of times in the second.
public static bool AreCollectionContentsEqual<T>(ICollection<T> collectionA, ICollection<T> collectionB)
where T : notnull
{
if (collectionA.Count != collectionB.Count)
{
return false;
}
Dictionary<T, int> countByValueDictionary = new(collectionA.Count);
foreach(T item in collectionA)
{
countByValueDictionary[item] = countByValueDictionary.TryGetValue(item, out int count)
? count + 1
: 1;
}
foreach (T item in collectionB)
{
if (!countByValueDictionary.TryGetValue(item, out int count) || count < 1)
{
return false;
}
countByValueDictionary[item] = count - 1;
}
return true;
}
These solutions should be optimal since their time and memory complexities are O(n), while the solutions that use ordering/sorting have time and memory complexities greater than O(n).