compare multiple arraylist lengths to find longest one - c#

I have 6 array lists and I would like to know which one is the longest without using a bunch of IF STATEMENTS.
"if arraylist.count > anotherlist.count Then...." <- Anyway to do this other than this?
Examples in VB.net or C#.Net (4.0) would be helpfull.
arraylist1.count
arraylist2.count
arraylist3.count
arraylist4.count
arraylist5.count
arraylist6.count
DIM longest As integer = .... 'the longest arraylist should be stored in this variable.
Thanks

Is 1 if statement acceptable?
public ArrayList FindLongest(params ArrayList[] lists)
{
var longest = lists[0];
for(var i=1;i<lists.Length;i++)
{
if(lists[i].Length > longest.Length)
longest = lists[i];
}
return longest;
}

You could use Linq:
public static ArrayList FindLongest(params ArrayList[] lists)
{
return lists == null
? null
: lists.OrderByDescending(x => x.Count).FirstOrDefault();
}
If you just want the length of the longest list, it's even simpler:
public static int FindLongestLength(params ArrayList[] lists)
{
return lists == null
? -1 // here you could also return (int?)null,
// all you need to do is adjusting the return type
: lists.Max(x => x.Count);
}

If you store everything in a List of Lists like for example
List<List<int>> f = new List<List<int>>();
Then a LINQ like
List<int> myLongest = f.OrderBy(x => x.Count).Last();
will yield the list with the most number of items. Of course you will have to handle the case when there is tie for the longest list

SortedList sl=new SortedList();
foreach (ArrayList al in YouArrayLists)
{
int c=al.Count;
if (!sl.ContainsKey(c)) sl.Add(c,al);
}
ArrayList LongestList=(ArrayList)sl.GetByIndex(sl.Count-1);

If you just want the length of the longest ArrayList:
public int FindLongest(params ArrayList[] lists)
{
return lists.Max(item => item.Count);
}
Or if you don't want to write a function and just want to in-line the code, then:
int longestLength = (new ArrayList[] { arraylist1, arraylist2, arraylist3,
arraylist4, arraylist5, arraylist6 }).Max(item => item.Count);

Related

C# LINQ sum array properties

So I have a class with an array of values, and a list of those classes.
And I want to return the sum (or any other operation) of all the items in the list, also as an array.
E.g. the sum of {1,2,3}, {10,20,30} & {100,200,300} would be {111,222,333}
So, the resulting array's 1st element will be the sum of all the 1st elements in the input arrays, the 2nd element will be the sum of all the 2nd elements in the input arrays, etc.
I can do it with:
public class Item
{
internal int[] Values = new int[3];
}
public class Items : List<Item>
{
internal int[] Values
{
get
{
int[] retVal = new int[3];
for (int x = 0; x < retVal.Length; x++)
{
retVal[x] = this.Sum(i => i.Values[x]);
}
return retVal;
}
}
}
But I feel that this should be achievable as a single line using LINQ. Is it?
Yes, this can be done using a single linq code line, using Enumrable.Range, Max, Select and Sum:
Notice I've also included a simple condition to save you from an IndexOutOfRangeException should one of the arrays is a different length than the others.
internal int[] ValuesLinq
{
get
{
return Enumerable
.Range(0, this.Max(i => i.Values.Length))
.Select(ind => this.Sum(item => item.Values.Length > ind ? item.Values[ind] : 0))
.ToArray();
}
}
You can see a live demo on Rextester
You can try to Group items withing the arrays by their indexes (so we sum all 1st arrays items, every 2nd items etc.):
int[] retVal = myList
.SelectMany(item => item.Values
.Select((value, index) => new {value, index}))
.GroupBy(item => item.index, item => item.value)
.Select(group => group.Sum())
.ToArray();

C# distinct List<string> by substring

I want to remove duplicates from a list of strings. I do this by using distinct, but i want to ignore the first char when comparing.
I already have a working code that deletes the duplicates, but my code also delete the first char of every string.
List<string> mylist = new List<string>();
List<string> newlist =
mylist.Select(e => e.Substring(1, e.Length - 1)).Distinct().ToList();
Input:
"1A","1B","2A","3C","4D"
Output:
"A","B","C","D"
Right Output:
"1A","2B","3C","4D" it doesn't matter if "1A" or "2A" will be deleted
I guess I am pretty close but.... any input is highly appreciated!
As always a solution should work as fast as possible ;)
You can implement an IEqualityComparer<string> that will compare your strings by ignoring the first letter. Then pass it to Distinct method.
myList.Distinct(new MyComparer());
There is also an example on MSDN that shows you how to implement and use a custom comparer with Distinct.
You can GroupBy all but the first character and take the first of every group:
List<string> result= mylist.GroupBy(s => s.Length < 2 ? s : s.Substring(1))
.Select(g => g.First())
.ToList();
Result:
Console.Write(string.Join(",", result)); // 1A,1B,3C,4D
it doesn't matter if "1A" or "2A" will be deleted
If you change your mind you have to replace g.First() with the new logic.
However, if performance really matters and it is never important which duplicate you want to delete you should prefer Selman's approach which suggests to write a custom IEqualityComparer<string>. That will be more efficient than my GroupBy approach if it's GetHashCode is implemented like:
return (s.Length < 2 ? s : s.Substring(1)).GetHashCode();
I'm going to suggest a simple extension that you can reuse in similar situations
public static IEnumerable<T> DistinctBy<T, U>(this IEnumerable<T> This, Func<T, U> keySelector)
{
var set = new HashSet<U>();
foreach (var item in This)
{
if (set.Add(keySelector(item)))
yield return item;
}
}
This is basically how Distinct is implemented in Linq.
Usage:
List<string> newlist =
mylist.DistinctBy(e => e.Substring(1, e.Length - 1)).ToList();
I realise the answer has already been given, but since I was working on this answer anyway I'm still going to post it, in case it's any use.
If you really want the fastest solution for large lists, then something like this might be optimal. You would need to do some accurate timings to be sure, though!
This approach does not make any additional string copies when comparing or computing the hash codes:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
internal static class Program
{
static void Main()
{
var myList = new List<string>
{
"1A",
"1B",
"2A",
"3C",
"4D"
};
var newList = myList.Distinct(new MyComparer());
Console.WriteLine(string.Join("\n", newList));
}
sealed class MyComparer: IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
if (x.Length != y.Length)
return false;
if (x.Length == 0)
return true;
return (string.Compare(x, 1, y, 1, x.Length) == 0);
}
public int GetHashCode(string s)
{
if (s.Length <= 1)
return 0;
int result = 17;
unchecked
{
bool first = true;
foreach (char c in s)
{
if (first)
first = false;
else
result = result*23 + c;
}
}
return result;
}
}
}
}

Index or Position of a string within an list of ienumerable strings [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to get the index of an element in an IEnumerable?
i have this following function that accepts ienumerable string list.
I loop through all the strings and if its value equals "TestName" (case insensitive), i return its position.
int GetMyTestColumnPosition(IEnumerable<string> TitleNames)
{
foreach (var test in TitleNames)
{
if (string.Compare(test, "testname", stringComparison.CurrentCultureIgnoreCase) == 0)
{
// return TitleNames.IndexOf(test); does not work!
}
}
}
EDIT: I changed the parameter to "IList<string>" and this works! But,
How to find index or position of a string within an ienumerable string list ?
Why does the ienumerable does not support index ? (we are not changing any value with in the list, we are just finding out its position!)
Well, since IEnumerables are used for enumerations, it's not such a surprise they don't have an IndexOf method. You can create an extension method if you want.
However, since you're already enumerating, what's the point of calculating the index again? Do something like this:
int index = 0;
foreach(var test in TitleNames)
{
if(...) return index;
index++;
}
Come to think of it, this is the extension method you want:
public static int IndexOf(this IEnumerable<T> list, T item)
{
int index = 0;
foreach(var l in list)
{
if(l.Equals(item))
return index;
index++;
}
return -1;
}
Just remember to add checks for nulls, and maybe supply an optional comparer.
You can pass the index in the overloads to Select or Where:
var found = TitleNames
.Select((str, index) => new { str, index })
.Where(x => x.str.Equals("testname", StringComparison.CurrentCultureIgnoreCase))
.FirstOrDefault();
if (found != null)
return found.index;
return -1;
From MSDN about IList
Represents a non-generic collection of objects that can be
individually accessed by index.
IEnumerable is a simple enumerator and does not support indexes.
var item =
TitleNames.Select( (tn, index) => new{tn, index})
.FirstOrDefault(x =>
string.Equals(x.tn,
"testname",
StringComparison.CurrentCultureIgnoreCase));
return item==null ? -1 : item.index;
TitleNames is IEnumerable, so it doesn't support indexes.
You can't rely on enumeration:
int i = 0;
foreach(var test in TitleNames)
{
i++;
}
to compute an index.
You could build your own class that inherits from IEnumerable<T> and that return objects on random order when enumerating.
If most concrete .Net types are generally index-friendly, it's pure implementation details.
So, to answer your question: you can't get index of object from IEnumerable<T>. Use IList<T> if you want index support.

search List<string> for string .StartsWith()

I have a
List<string>
with 1500 strings. I am now using the following code to pull out only string that start with the string prefixText.
foreach(string a in <MYLIST>)
{
if(a.StartsWith(prefixText, true, null))
{
newlist.Add(a);
}
}
This is pretty fast, but I'm looking for google fast. Now my question is if I arrange the List in alphabetical order, then compare char by char can I make this faster? Or any other suggestions on making this faster?
Thus 1500 is not really a huge number binary search on sorted list would be enough probably.
Nevertheless most efficient algorithms for prefix search are based on the data structure named Trie or Prefix Tree. See: http://en.wikipedia.org/wiki/Trie
Following picture demonstrates the idea very briefly:
For c# implementation see for instance .NET DATA STRUCTURES FOR PREFIX STRING SEARCH AND SUBSTRING (INFIX) SEARCH TO IMPLEMENT AUTO-COMPLETION AND INTELLI-SENSE
You can use PLINQ (Parallel LINQ) to make the execution faster:
var newList = list.AsParallel().Where(x => x.StartsWith(prefixText)).ToList()
If you have the list in alpabetical order, you can use a variation of binary search to make it a lot faster.
As a starting point, this will return the index of one of the strings that match the prefix, so then you can look forward and backward in the list to find the rest:
public static int BinarySearchStartsWith(List<string> words, string prefix, int min, int max) {
while (max >= min) {
int mid = (min + max) / 2;
int comp = String.Compare(words[mid].Substring(0, prefix.Length), prefix);
if (comp < 0) {
min = mid + 1;
} else if (comp > 0) {
max = mid - 1;
} else {
return mid;
}
}
return -1;
}
int index = BinarySearchStartsWith(theList, "pre", 0, theList.Count - 1);
if (index == -1) {
// not found
} else{
// found
}
Note: If you use a prefix that is longer than any of the strings that are compared, it will break, so you might need to figure out how you want to handle that.
So many approches were analyzed to achive minimum data capacity and high performance. The first place is: all prefixes are stored in dictionary: key - prefix, values - items appropriate for prefix.
Here simple implementation of this algorithm:
public class Trie<TItem>
{
#region Constructors
public Trie(
IEnumerable<TItem> items,
Func<TItem, string> keySelector,
IComparer<TItem> comparer)
{
this.KeySelector = keySelector;
this.Comparer = comparer;
this.Items = (from item in items
from i in Enumerable.Range(1, this.KeySelector(item).Length)
let key = this.KeySelector(item).Substring(0, i)
group item by key)
.ToDictionary( group => group.Key, group => group.ToList());
}
#endregion
#region Properties
protected Dictionary<string, List<TItem>> Items { get; set; }
protected Func<TItem, string> KeySelector { get; set; }
protected IComparer<TItem> Comparer { get; set; }
#endregion
#region Methods
public List<TItem> Retrieve(string prefix)
{
return this.Items.ContainsKey(prefix)
? this.Items[prefix]
: new List<TItem>();
}
public void Add(TItem item)
{
var keys = (from i in Enumerable.Range(1, this.KeySelector(item).Length)
let key = this.KeySelector(item).Substring(0, i)
select key).ToList();
keys.ForEach(key =>
{
if (!this.Items.ContainsKey(key))
{
this.Items.Add(key, new List<TItem> { item });
}
else if (this.Items[key].All(x => this.Comparer.Compare(x, item) != 0))
{
this.Items[key].Add(item);
}
});
}
public void Remove(TItem item)
{
this.Items.Keys.ToList().ForEach(key =>
{
if (this.Items[key].Any(x => this.Comparer.Compare(x, item) == 0))
{
this.Items[key].RemoveAll(x => this.Comparer.Compare(x, item) == 0);
if (this.Items[key].Count == 0)
{
this.Items.Remove(key);
}
}
});
}
#endregion
}
1500 is usually too few:
you could search it in parallel with a simple divide and conquer of the problem. Search each half of the list in two (or divide into three, four, ..., parts) different jobs/threads.
Or store the strings in a (not binary) tree instead. Will be O(log n).
sorted in alphabetical order you can do a binary search (sort of the same as the previous one)
You can accelerate a bit by comparing the first character before invoking StartsWith:
char first = prefixText[0];
foreach(string a in <MYLIST>)
{
if (a[0]==first)
{
if(a.StartsWith(prefixText, true, null))
{
newlist.Add(a);
}
}
}
I assume that the really fastest way would be to generate a dictionary with all possible prefixes from your 1500 strings, effectively precomputing the results for all possible searches that will return non-empty. Your search would then be simply a dictionary lookup completing in O(1) time. This is a case of trading memory (and initialization time) for speed.
private IDictionary<string, string[]> prefixedStrings;
public void Construct(IEnumerable<string> strings)
{
this.prefixedStrings =
(
from s in strings
from i in Enumerable.Range(1, s.Length)
let p = s.Substring(0, i)
group s by p
).ToDictionary(
g => g.Key,
g => g.ToArray());
}
public string[] Search(string prefix)
{
string[] result;
if (this.prefixedStrings.TryGetValue(prefix, out result))
return result;
return new string[0];
}
Have you tried implementing a Dictionary and comparing the results? Or, if you do put the entries in alphabetical order, try a binary search.
The question to me is whether or not you'll need to do this one time or multiple times.
If you only find the StartsWithPrefix list one time, you can't get faster then leaving the original list as is and doing myList.Where(s => s.StartsWith(prefix)). This looks at every string one time so it's O(n)
If you need to find the StartsWithPrefix list several times, or maybe you're going to want to add or remove strings to the original list and update the StartsWithPrefix list then you should sort the original list and use binary search. But this will be sort time + search time = O(n log n) + 2 * O(log n)
If you did the binary search method, you would find the indexes of the first occurrence of your prefix and the last occurrence via search. Then do mySortedList.Skip(n).Take(m-n) where n is first index and m is last index.
Edit:
Wait a minute, we're using the wrong tool for the job. Use a Trie! If you put all your strings into a Trie instead of the list, all you have to do is walk down the trie with your prefix and grab all the words underneath that node.
I would go with using Linq:
var query = list.Where(w => w.StartsWith("prefixText")).Select(s => s).ToList();

c# comparing arrays

good afternoon everybody
the question is kinda simple but I've been having problems the whole afternoon
i have 2 lists:
list of ints (ids)
list of objects (that contains ids)
and i want to compare them but i want to obtain the id that doesn't have a pair (if it exists)
i was wondering if there's a c# or linq method to identify the values that are different in two arrays
example
if i have
List<int> ids = {1,2,3,4,5}
and
List<objectX> x = (contains id,code, and description)
and i was trying something like
foreach (int id in ids)
{
foreach (objectX item in x)
{
if (item.id == id)
{
break;
}
else
idDiferentes.Add(id);
}
}
but like you can imagine it doesn't work
for example
ids= {1,2,3,4}
objectx[id] ={1,3,2}
the ids are different when i compare them so i get a bigger list that the one i need
i also tried with an linq outer join but i don't understand how it works pretty well
var idsWithoutObjects = ids.Except(x.Select(item => item.id));
What you are after is the Except extension method. It gives you the set difference between two sequences.
So you can do something like this (pseudo c#-code):
var idDifferences = x.Select(item => item.id).Except(ids);
Linq Set Operations:
int[] A = { 1 , 2 , 3 , 4 , 5 , } ;
int[] B = { 2 , 3 , 4 , 5 , 6 , } ;
int[] A_NotIn_B = A.Except( B ).ToArray() ;
int[] B_NotIn_A = B.Except( A ).ToArray() ;
There you go.
As an alternative to LINQ (although LINQ is probably the right answer here), if all your ids are unique you may be able to use the Contains() method, for example:
foreach(objectX item in x)
{
if(!ids.Contains(item.id))
{
idDiferentes.Add(item.id);
}
}
It is easier to use a flag, e.g.:
bool b = False;
foreach (int id in ids)
{
foreach (objectX item in x)
{
if (item.id == id)
{
b = True;
break;
}
}
}
if (!b)
{
idDiferentes.Add(id);
}

Categories