Related
I want to get the index of an array which I have done with Array.IndexOf(array, value). This works good with one value but I want to get every occurrence of the value and store the index's into another array. For example, the name 'tom' appears 5 times in an array, I want to find the index positions of each one.
Maybe something like this? This uses a list rather than an array, but it follows the same idea.
List<int> Indexes = new List<int>();
for (int i = 0; i < array.Count(); i++)
{
if (array[i] == "tom")
{
Indexes.Add(i);
}
}
This solution is like the previous one, but will run faster:
string value = "tom";
int[] indices = stringArray.Where(s => s != null)
.Select((s, i) => s.Equals(value) ? i: -1)
.Where(i => i >= 0)
.ToArray();
If I'm not mistaken, you can add another parameter to IndexOf(), which will let you specify where in the array to start. This should give you more or less what you need:
var indices = new List<int>();
int i = Array.IndexOf(array, val);
while(i > -1){
indices.Add(i);
i = Array.IndexOf(array, val, i+1);
}
// ... and if it is important to have the result as an array:
int[] result = indices.ToArray();
Practical example:
var array = new int[]{ 1, 2, 3, 3, 4, 5, 3, 6, 7, 8, 3};
int val = 3;
var indices = new List<int>();
int i = Array.IndexOf(array, val);
while(i > -1){
indices.Add(i);
i = Array.IndexOf(array, val, i+1);
}
// ... and if it is important to have the result as an array:
int[] result = indices.ToArray();
Edit: Just realized a while-loop may well be a lot cleaner than a for-loop for this.
Edit 2: Due to popular demand (see comment below), here`s the original beautiful non-basic for-loop, re-introduced just for your reading pleasure:
for(int i = Array.IndexOf(array, val); i > -1; i = Array.IndexOf(array, val, i+1)){
indices.Add(i);
}
Could create an extension method to do it
namespace Extensions
{
public static class ArrayExtension
{
public static IEnumerable<int> GetIndicesOf<T>(this T[] target, T val, int start = 0)
{
EqualityComparer<T> comparer = EqualityComparer<T>.Default;
for (int i = start; i < target.Length; i++)
{
if (comparer.Equals(target[i], val))
{
yield return i;
}
}
}
}
}
Add the using statement for your namespace with the extension method using Extensions; in the file you want to call it in.
Then to call it just do the following to get the indices.
IEnumerable<int> indices = array.GetIndicesOf(value);
or to get an array just do
int[] indicies = array.GetIndicesOf(value).ToArray();
You can use LINQ's Select overload which uses elements index as well, like:
var indices = stringArray.Select((s, i) => new {Value = s, Index = i})
.Where(r => r.Value == "tom")
.Select(r => r.Index);
I have a query which I get as:
var query = Data.Items
.Where(x => criteria.IsMatch(x))
.ToList<Item>();
This works fine.
However now I want to break up this list into x number of lists, for example 3. Each list will therefore contain 1/3 the amount of elements from query.
Can it be done using LINQ?
You can use PLINQ partitioners to break the results into separate enumerables.
var partitioner = Partitioner.Create<Item>(query);
var partitions = partitioner.GetPartitions(3);
You'll need to reference the System.Collections.Concurrent namespace. partitions will be a list of IEnumerable<Item> where each enumerable returns a portion of the query.
I think something like this could work, splitting the list into IGroupings.
const int numberOfGroups = 3;
var groups = query
.Select((item, i) => new { item, i })
.GroupBy(e => e.i % numberOfGroups);
You can use Skip and Take in a simple for to accomplish what you want
var groupSize = (int)Math.Ceiling(query.Count() / 3d);
var result = new List<List<Item>>();
for (var j = 0; j < 3; j++)
result.Add(query.Skip(j * groupSize).Take(groupSize).ToList());
If the order of the elements doesn't matter using an IGrouping as suggested by Daniel Imms is probably the most elegant way (add .Select(gr => gr.Select(e => e.item)) to get an IEnumerable<IEnumerable<T>>).
If however you want to preserve the order you need to know the total number of elements. Otherwise you wouldn't know when to start the next group. You can do this with LINQ but it requires two enumerations: one for counting and another for returning the data (as suggested by Esteban Elverdin).
If enumerating the query is expensive you can avoid the second enumeration by turning the query into a list and then use the GetRange method:
public static IEnumerable<List<T>> SplitList<T>(List<T> list, int numberOfRanges)
{
int sizeOfRanges = list.Count / numberOfRanges;
int remainder = list.Count % numberOfRanges;
int startIndex = 0;
for (int i = 0; i < numberOfRanges; i++)
{
int size = sizeOfRanges + (remainder > 0 ? 1 : 0);
yield return list.GetRange(startIndex, size);
if (remainder > 0)
{
remainder--;
}
startIndex += size;
}
}
static void Main()
{
List<int> list = Enumerable.Range(0, 10).ToList();
IEnumerable<List<int>> result = SplitList(list, 3);
foreach (List<int> values in result)
{
string s = string.Join(", ", values);
Console.WriteLine("{{ {0} }}", s);
}
}
The output is:
{ 0, 1, 2, 3 }
{ 4, 5, 6 }
{ 7, 8, 9 }
You can create an extension method:
public static IList<List<T>> GetChunks<T>(this IList<T> items, int numOfChunks)
{
if (items.Count < numOfChunks)
throw new ArgumentException("The number of elements is lower than the number of chunks");
int div = items.Count / numOfChunks;
int rem = items.Count % numOfChunks;
var listOfLists = new List<T>[numOfChunks];
for (int i = 0; i < numOfChunks; i++)
listOfLists[i] = new List<T>();
int currentGrp = 0;
int currRemainder = rem;
foreach (var el in items)
{
int currentElementsInGrp = listOfLists[currentGrp].Count;
if (currentElementsInGrp == div && currRemainder > 0)
{
currRemainder--;
}
else if (currentElementsInGrp >= div)
{
currentGrp++;
}
listOfLists[currentGrp].Add(el);
}
return listOfLists;
}
then use it like this :
var chunks = query.GetChunks(3);
N.B.
in case of number of elements not divisible by the number of groups, the first groups will be bigger. e.g. [0,1,2,3,4] --> [0,1] - [2,3] - [4]
List<Int32> dansConList = new List<Int32>();
dansConList[0] = 1;
dansConList[1] = 2;
dansConList[2] = 3;
List<Int32> dansRandomList = new List<Int32>();
dansRandomList[0] = 1;
dansRandomList[1] = 2;
dansRandomList[2] = 4;
I need a method that, when evaluating the above lists, will return false for dansRandomList and true for dansConList based on the fact dansConList has a consecutive number sequence in it's values, and dansRandomList does not (missing the value 3).
Using LINQ is preferable, if possible.
What I've Tried:
For the sake of achieving the end result, I have used a for loop and compare with 'i' (loop counter) to evaluate the values, but as mentioned above I'd like to use LINQ for this.
One-liner, only iterates until the first non-consecutive element:
bool isConsecutive = !myIntList.Select((i,j) => i-j).Distinct().Skip(1).Any();
Update: a couple examples of how this works:
Input is { 5, 6, 7, 8 }
Select yields { (5-0=)5, (6-1=)5, (7-2=)5, (8-3=)5 }
Distinct yields { 5, (5 not distinct, 5 not distinct, 5 not distinct) }
Skip yields { (5 skipped, nothing left) }
Any returns false
Input is { 1, 2, 6, 7 }
Select yields { (1-0=)1, (2-1=)1, (6-2=)4, (7-3=)4 } *
Distinct yields { 1, (1 not distinct,) 4, (4 not distinct) } *
Skip yields { (1 skipped,) 4 }
Any returns true
* The Select will not yield the second 4 and the Distinct will not check it, as the Any will stop after finding the first 4.
var min = list.Min();
var max = list.Max();
var all = Enumerable.Range(min, max - min + 1);
return list.SequenceEqual(all);
var result = list
.Zip(list.Skip(1), (l, r) => l + 1 == r)
.All(t => t);
You can use this extension method:
public static bool IsConsecutive(this IEnumerable<int> ints )
{
//if (!ints.Any())
// return true; //Is empty consecutive?
// I think I prefer exception for empty list but I guess it depends
int start = ints.First();
return !ints.Where((x, i) => x != i+start).Any();
}
Use it like this:
[Test]
public void ConsecutiveTest()
{
var ints = new List<int> {1, 2, 4};
bool isConsecutive = ints.IsConsecutive();
}
Extension method:
public static bool IsConsecutive(this IEnumerable<int> myList)
{
return myList.SequenceEqual(Enumerable.Range(myList.First(), myList.Last()));
}
Useage:
bool isConsecutive = dansRandomList.IsConsecutive();
Caveat: returns true if empty.
var list = new int[] {-1,0,1,2,3};
var isConsecutive = list.Select((n,index) => n == index+list.ElementAt(0)).All (n => n);
Here is the another one. It supports {1,2,3,4} and {4,3,2,1} both. It tests sequential number differences equals 1 or -1.
Function IsConsecutive(ints As IEnumerable(Of Integer)) As Boolean
If ints.Count > 1 Then
Return Enumerable.Range(0, ints.Count - 1).
All(Function(r) ints(r) + 1 = ints(r + 1) OrElse ints(r) - 1 = ints(r + 1))
End If
Return False
End Function
In order to check whether the series contain consecutive number or not you may use this
Sample
isRepeatable(121878999, 2);
Result = True
since 9 repeats two times , where upto is no of times in series
isRepeatable(37302293, 3)
Result = False
since no number repeat 3 times in series
static bool isRepeatable(int num1 ,int upto)
{
List<int> myNo = new List<int>();
int previous =0;
int series = 0;
bool doesMatch = false;
var intList = num1.ToString().Select(x => Convert.ToInt32(x.ToString())).ToList();
for (int i = 0; i < intList.Count; i++)
{
if (myNo.Count==0)
{
myNo.Add(intList[i]);
previous = intList[i];
series += 1;
}
else
{
if (intList[i]==previous)
{
series += 1;
if (series==upto)
{
doesMatch = true;
break;
}
}
else
{
myNo = new List<int>();
previous = 0;
series = 0;
}
}
}
return doesMatch;
}
// 1 | 2 | 3 | 4 | _
// _ | 1 | 2 | 3 | 4
// | 1 | 1 | 1 | => must be 1 (or 2 for even/odd consecutive integers)
var numbers = new List<int>() { 1, 2, 3, 4, 5 };
const step = 1; // change to 2 for even and odd consecutive integers
var isConsecutive = numbers.Skip(1)
.Zip(numbers.SkipLast(1))
.Select(n => {
var diff = n.First - n.Second;
return (IsValid: diff == step, diff);
})
.Where(diff => diff.IsValid)
.Distinct()
.Count() == 1;
Or we could write that a bit shorter but less readable:
var isConsecutive = numbers.Skip(1)
.Zip(numbers.SkipLast(1), (l, r) => (IsValid: (l-r == step), l-r))
.Where(diff => diff.IsValid)
.Distinct()
.Count() == 1;
Old question, but here's an easy way using some simple algebra.
This only works if your integers start at 1 though.
public bool AreIntegersConsecutive(List<int> integers)
{
var sum = integers.Sum();
var count = integers.Count();
var expectedSum = (count * (count + 1)) / 2;
return expectedSum == sum;
}
It is works for unique list only.
List<Int32> dansConList = new List<Int32>();
dansConList.Add(7);
dansConList.Add(8);
dansConList.Add(9);
bool b = (dansConList.Min() + dansConList.Max())*((decimal)dansConList.Count())/2.0m == dansConList.Sum();
Here is an extension method that uses the Aggregate function.
public static bool IsConsecutive(this List<Int32> value){
return value.OrderByDescending(c => c)
.Select(c => c.ToString())
.Aggregate((current, item) =>
(item.ToInt() - current.ToInt() == -1) ? item : ""
)
.Any();
}
Usage:
var consecutive = new List<Int32>(){1,2,3,4}.IsConsecutive(); //true
var unorderedConsecutive = new List<Int32>(){1,4,3,2}.IsConsecutive(); //true
var notConsecutive = new List<Int32>(){1,5,3,4}.IsConsecutive(); //false
Here is a C version code, I think it's easy to rewrite it in other language based on the logical.
int isConsecutive(int *array, int length) {
int i = 1;
for (; i < length; i++) {
if (array[i] != array[i - 1] + 1)
return 0; //which means false and it's not a consecutive list
}
return 1;
}
Is there a way to merge(union without dupes) two given lists into one and store the items in sorted way by using ONE for loop?
Also, i am looking for a solution which does not makes use of API methods ( like, union, sort etc).
Sample Code.
private static void MergeAndOrder()
{
var listOne = new List<int> {3, 4, 1, 2, 7, 6, 9, 11};
var listTwo = new List<int> {1, 7, 8, 3, 5, 10, 15, 12};
//Without Using C# helper methods...
//ToDo.............................
//Using C# APi.
var expectedResult = listOne.Union(listTwo).ToList();
expectedResult.Sort();//Output: 1,2,3,4,5,6,7,8,9,10,11,12,15
//I need the same result without using API methods, and that too by iterating over items only once.
}
PS: I have been asked this question in an interview, but couldn't find answer as yet.
Why can't you use the api methods? Re-inventing the wheel is dumb. Also, it's the .ToList() call that's killing you. Never call .ToList() or .ToArray() until you absolutely have to, because they break your lazy evaluation.
Do it like this and you'll enumerate the lists with the minimum amount necessary:
var expectedResult = listOne.Union(listTwo).OrderBy(i => i);
This will do the union in one loop using a hashset, and lazy execution means the base-pass for the sort will piggyback on the union. But I don't think it's possible finish the sort in a single iteration, because sorting is not a O(n) operation.
Without the precondition that both lists are sorted before the merge + sort operation, you can't do this in O(n) time (or "using one loop").
Add that precondition and the problem is very easy.
Keep two iterators, one for each list. On each loop, compare the element from each list and choose the smaller. Increment that list's iterator. If the element you are about to insert in the final list is already the last element in that list, skip the insert.
In pseudocode:
List a = { 1, 3, 5, 7, 9 }
List b = { 2, 4, 6, 8, 10 }
List result = { }
int i=0, j=0, lastIndex=0
while(i < a.length || j < b.length)
// If we're done with a, just gobble up b (but don't add duplicates)
if(i >= a.length)
if(result[lastIndex] != b[j])
result[++lastIndex] = b[j]
j++
continue
// If we're done with b, just gobble up a (but don't add duplicates)
if(j >= b.length)
if(result[lastIndex] != a[i])
result[++lastIndex] = a[i]
i++
continue
int smallestVal
// Choose the smaller of a or b
if(a[i] < b[j])
smallestVal = a[i++]
else
smallestVal = b[j++]
// Don't insert duplicates
if(result[lastIndex] != smallestVal)
result[++lastIndex] = smallestVal
end while
private static void MergeTwoSortedArray(int[] first, int[] second)
{
//throw new NotImplementedException();
int[] result = new int[first.Length + second.Length];
int i=0 , j=0 , k=0;
while(i < first.Length && j <second.Length)
{
if(first[i] < second[j])
{
result[k++] = first[i++];
}
else
{
result[k++] = second[j++];
}
}
if (i < first.Length)
{
for (int a = i; a < first.Length; a++)
result[k] = first[a];
}
if (j < second.Length)
{
for (int a = j; a < second.Length; a++)
result[k++] = second[a];
}
foreach (int a in result)
Console.Write(a + " ");
Console.WriteLine();
}
Using iterators and streaming interface the task is not that complicated:
class MergeTwoSortedLists
{
static void Main(string[] args) {
var list1 = new List<int?>() {
1,3,5,9,11
};
var list2 = new List<int?>() {
2,5,6,11,15,17,19,29
};
foreach (var c in SortedAndMerged(list1.GetEnumerator(), list2.GetEnumerator())) {
Console.Write(c+" ");
}
Console.ReadKey();
}
private static IEnumerable<int> SortedAndMerged(IEnumerator<int?> e1, IEnumerator<int?> e2) {
e2.MoveNext();
e1.MoveNext();
do {
while (e1.Current < e2.Current) {
if (e1.Current != null) yield return e1.Current.Value;
e1.MoveNext();
}
if (e2.Current != null) yield return e2.Current.Value;
e2.MoveNext();
} while (!(e1.Current == null && e2.Current == null));
}
}
Try this:
public static IEnumerable<T> MergeWith<T>(IEnumerable<T> collection1, IEnumerable<T> collection2,
IComparer<T> comparer)
{
using (var enumerator1 = collection1.GetEnumerator())
using (var enumerator2 = collection2.GetEnumerator())
{
var isMoveNext1 = enumerator1.MoveNext();
var isMoveNext2 = enumerator2.MoveNext();
do
{
while (comparer.Compare(enumerator1.Current, enumerator2.Current) < 0 || !isMoveNext2)
{
if (isMoveNext1)
yield return enumerator1.Current;
else
break;
isMoveNext1 = enumerator1.MoveNext();
}
if (isMoveNext2)
yield return enumerator2.Current;
isMoveNext2 = enumerator2.MoveNext();
} while (isMoveNext1 || isMoveNext2);
}
}
You could write a loop that merges and de-dups the lists and uses a binary-search approach to insert new values into the destination list.
var listOne = new List<int> { 3, 4, 1, 2, 7, 6, 9, 11 };
var listTwo = new List<int> { 1, 7, 8, 3, 5, 10, 15, 12 };
var result = listOne.ToList();
foreach (var n in listTwo)
{
if (result.IndexOf(n) == -1)
result.Add(n);
}
The closest solution I see would be to allocate an array knowing that integers are bounded to some value.
int[] values = new int[ Integer.MAX ]; // initialize with 0
int size1 = list1.size();
int size2 = list2.size();
for( int pos = 0; pos < size1 + size2 ; pos++ )
{
int val = pos > size1 ? list2[ pos-size1 ] : list1[ pos ] ;
values[ val ]++;
}
Then you can argue that you have the sorted array in a "special" form :-) To get a clean sorted array, you need to traverse the values array, skip all position with 0 count, and build the final list.
This will only work for lists of integers, but happily that is what you have!
List<int> sortedList = new List<int>();
foreach (int x in listOne)
{
sortedList<x> = x;
}
foreach (int x in listTwo)
{
sortedList<x> = x;
}
This is using the values in each list as the index position at which to store the value. Any duplicate values will overwrite the previous entry at that index position. It meets the requirement of only one iteration over the values.
It does of course mean that there will be 'empty' positions in the list.
I suspect the job position has been filled by now though.... :-)
I know how to do this in an ugly way, but am wondering if there is a more elegant and succinct method.
I have a string array of e-mail addresses. Assume the string array is of arbitrary length -- it could have a few items or it could have a great many items. I want to build another string consisting of say, 50 email addresses from the string array, until the end of the array, and invoke a send operation after each 50, using the string of 50 addresses in the Send() method.
The question more generally is what's the cleanest/clearest way to do this kind of thing. I have a solution that's a legacy of my VBScript learnings, but I'm betting there's a better way in C#.
You want elegant and succinct, I'll give you elegant and succinct:
var fifties = from index in Enumerable.Range(0, addresses.Length)
group addresses[index] by index/50;
foreach(var fifty in fifties)
Send(string.Join(";", fifty.ToArray());
Why mess around with all that awful looping code when you don't have to? You want to group things by fifties, then group them by fifties.
That's what the group operator is for!
UPDATE: commenter MoreCoffee asks how this works. Let's suppose we wanted to group by threes, because that's easier to type.
var threes = from index in Enumerable.Range(0, addresses.Length)
group addresses[index] by index/3;
Let's suppose that there are nine addresses, indexed zero through eight
What does this query mean?
The Enumerable.Range is a range of nine numbers starting at zero, so 0, 1, 2, 3, 4, 5, 6, 7, 8.
Range variable index takes on each of these values in turn.
We then go over each corresponding addresses[index] and assign it to a group.
What group do we assign it to? To group index/3. Integer arithmetic rounds towards zero in C#, so indexes 0, 1 and 2 become 0 when divided by 3. Indexes 3, 4, 5 become 1 when divided by 3. Indexes 6, 7, 8 become 2.
So we assign addresses[0], addresses[1] and addresses[2] to group 0, addresses[3], addresses[4] and addresses[5] to group 1, and so on.
The result of the query is a sequence of three groups, and each group is a sequence of three items.
Does that make sense?
Remember also that the result of the query expression is a query which represents this operation. It does not perform the operation until the foreach loop executes.
Seems similar to this question: Split a collection into n parts with LINQ?
A modified version of Hasan Khan's answer there should do the trick:
public static IEnumerable<IEnumerable<T>> Chunk<T>(
this IEnumerable<T> list, int chunkSize)
{
int i = 0;
var chunks = from name in list
group name by i++ / chunkSize into part
select part.AsEnumerable();
return chunks;
}
Usage example:
var addresses = new[] { "a#example.com", "b#example.org", ...... };
foreach (var chunk in Chunk(addresses, 50))
{
SendEmail(chunk.ToArray(), "Buy V14gr4");
}
It sounds like the input consists of separate email address strings in a large array, not several email address in one string, right? And in the output, each batch is a single combined string.
string[] allAddresses = GetLongArrayOfAddresses();
const int batchSize = 50;
for (int n = 0; n < allAddresses.Length; n += batchSize)
{
string batch = string.Join(";", allAddresses, n,
Math.Min(batchSize, allAddresses.Length - n));
// use batch somehow
}
Assuming you are using .NET 3.5 and C# 3, something like this should work nicely:
string[] s = new string[] {"1", "2", "3", "4"....};
for (int i = 0; i < s.Count(); i = i + 50)
{
string s = string.Join(";", s.Skip(i).Take(50).ToArray());
DoSomething(s);
}
I would just loop through the array and using StringBuilder to create the list (I'm assuming it's separated by ; like you would for email). Just send when you hit mod 50 or the end.
void Foo(string[] addresses)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < addresses.Length; i++)
{
sb.Append(addresses[i]);
if ((i + 1) % 50 == 0 || i == addresses.Length - 1)
{
Send(sb.ToString());
sb = new StringBuilder();
}
else
{
sb.Append("; ");
}
}
}
void Send(string addresses)
{
}
I think we need to have a little bit more context on what exactly this list looks like to give a definitive answer. For now I'm assuming that it's a semicolon delimeted list of email addresses. If so you can do the following to get a chunked up list.
public IEnumerable<string> DivideEmailList(string list) {
var last = 0;
var cur = list.IndexOf(';');
while ( cur >= 0 ) {
yield return list.SubString(last, cur-last);
last = cur + 1;
cur = list.IndexOf(';', last);
}
}
public IEnumerable<List<string>> ChunkEmails(string list) {
using ( var e = DivideEmailList(list).GetEnumerator() ) {
var list = new List<string>();
while ( e.MoveNext() ) {
list.Add(e.Current);
if ( list.Count == 50 ) {
yield return list;
list = new List<string>();
}
}
if ( list.Count != 0 ) {
yield return list;
}
}
}
I think this is simple and fast enough.The example below divides the long sentence into 15 parts,but you can pass batch size as parameter to make it dynamic.Here I simply divide using "/n".
private static string Concatenated(string longsentence)
{
const int batchSize = 15;
string concatanated = "";
int chanks = longsentence.Length / batchSize;
int currentIndex = 0;
while (chanks > 0)
{
var sub = longsentence.Substring(currentIndex, batchSize);
concatanated += sub + "/n";
chanks -= 1;
currentIndex += batchSize;
}
if (currentIndex < longsentence.Length)
{
int start = currentIndex;
var finalsub = longsentence.Substring(start);
concatanated += finalsub;
}
return concatanated;
}
This show result of split operation.
var parts = Concatenated(longsentence).Split(new string[] { "/n" }, StringSplitOptions.None);
Extensions methods based on Eric's answer:
public static IEnumerable<IEnumerable<T>> SplitIntoChunks<T>(this T[] source, int chunkSize)
{
var chunks = from index in Enumerable.Range(0, source.Length)
group source[index] by index / chunkSize;
return chunks;
}
public static T[][] SplitIntoArrayChunks<T>(this T[] source, int chunkSize)
{
var chunks = from index in Enumerable.Range(0, source.Length)
group source[index] by index / chunkSize;
return chunks.Select(e => e.ToArray()).ToArray();
}