Generating Numbers in sequence - c#

How can i generate numbers using LinQ in this sequence given the startIndex,count of numbers and the maximum number.For example:
Sample Numbers = 1,2,3,4
StartIndex = 1 (i.e it should start from 1)
Sequence number count = 3
Maximum number = 4 (i.e till 4)
Expected result given the above details :
1,2,3
1,3,4
1,2,4
Is there a way to do it using linQ?

If you didn't need the length of you sequences to be dynamic, then you could use:
var startindex=1;
var maxindex=4;
var data = Enumerable.Range(startindex,maxindex);
var qry = from x in data
where x == startindex
from y in data
where x < y
from z in data
where y < z
select new { x, y, z };
foreach (var tuple in qry) {
Console.WriteLine("{0} {1} {2}", tuple.x, tuple.y, tuple.z);
}
The sequence length is hardcoded to 3, because there are 3 enumerables being joined: x, y, z.
If you want to dynamically join an arbitrary number of enumerables, then you can use Eric Lippert's Cartesian Product Linq example.
You pass a set of k sequences of N items, and it will return a set of all combinations of length k.
Now, you don't want repeated elements in your results.
So, I added the following to Eric's example:
where accseq.All(accitem => accitem < item)
Here's the final solution (edited for clarity):
var startindex=1;
var maxindex=7;
var count = 3;
// Make a set of count-1 sequences, whose values range from startindex+1 to maxindex
List<List<int>> sequences = new List<List<int>>();
// We only want permutations starting with startindex. So, the first input sequence to be joined should only have the value startindex.
List<int> list1 = new List<int>();
list1.Add(startindex);
sequences.Add(list1);
// The rest of the input sequences to be joined should contain the range startindex+1 .. maxindex
for (int i=1; i< count; i++)
{
sequences.Add(Enumerable.Range(startindex+1,maxindex-startindex).ToList());
}
// Generate the permutations of the input sequences
IEnumerable<IEnumerable<int>> emptyProduct = new[] { Enumerable.Empty<int>() };
var result = sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
where accseq.All(accitem => accitem < item)
select accseq.Concat(new[] {item}));
// Show the result
foreach (var x in result)
{
Console.WriteLine(x);
}

Try this function.
public static IEnumerable<IEnumerable<T>> Permute<T>(IEnumerable<T> list)
{
if (list.Count() == 1)
return new List<IEnumerable<T>> { list };
return list.Select((a, i1) => Permute(list.Where((b, i2) => i2 != i1)).Select(b => (new List<T> { a }).Union(b)))
.SelectMany(c => c);
}
//Here Range(startindex, count)
List<int> list1 = Enumerable.Range(1, 3).ToList();
//generates all permutations
var permutationlist = Permute(list1);

Okay, first let's state the problem clearly. I'll assume your numbers are int but that's a mostly irrelevant detail but the concreteness makes thinking go more smo
You have a sequence a_0, a_1, a_2, ..., a_N of int.
You have an integer k satisfying 1 <= k <= N + 1.
You have a starting index start >=0 and an ending index end <= N.
You want all subsequences a_i0, a_i1, a_i2, ..., a_ik of length k such that i0 = start and ik = end.
Then your algorithm is simple. You want to produce all combinations of size k - 2 of { start + 1, ..., end - 1 }. Given such a combination j1, j2, ..., j(k-1), order it, call the resulting ordered sequence i1, i2, ..., i(k-1) and return the sequence a_start, a_i1, a_i2, ..., a_i(k-1), a_end.
Now that you know a formal statement of the problem, and what you need to solve it, resources abound for generating said combinations. cf. Google search : Generating combinations C# or Knuth Volume 4A.

Related

How can calculate the mode using array. Im only a beginner in programming. its for our finals project [duplicate]

This question already has answers here:
Find character with most occurrences in string?
(12 answers)
Closed 7 years ago.
I want to find the Mode in an Array. I know that I have to do nested loops to check each value and see how often the element in the array appears. Then I have to count the number of times the second element appears. The code below doesn't work, can anyone help me please.
for (int i = 0; i < x.length; i ++)
{
x[i]++;
int high = 0;
for (int i = 0; i < x.length; i++)
{
if (x[i] > high)
high = x[i];
}
}
Using nested loops is not a good way to solve this problem. It will have a run time of O(n^2) - much worse than the optimal O(n).
You can do it with LINQ by grouping identical values and then finding the group with the largest count:
int mode = x.GroupBy(v => v)
.OrderByDescending(g => g.Count())
.First()
.Key;
This is both simpler and faster. But note that (unlike LINQ to SQL) LINQ to Objects currently doesn't optimize the OrderByDescending when only the first result is needed. It fully sorts the entire result set which is an O(n log n) operation.
You might want this O(n) algorithm instead. It first iterates once through the groups to find the maximum count, and then once more to find the first corresponding key for that count:
var groups = x.GroupBy(v => v);
int maxCount = groups.Max(g => g.Count());
int mode = groups.First(g => g.Count() == maxCount).Key;
You could also use the MaxBy extension from MoreLINQ method to further improve the solution so that it only requires iterating through all elements once.
A non LINQ solution:
int[] x = new int[] { 1, 2, 1, 2, 4, 3, 2 };
Dictionary<int, int> counts = new Dictionary<int, int>();
foreach( int a in x ) {
if ( counts.ContainsKey(a) )
counts[a] = counts[a]+1
else
counts[a] = 1
}
int result = int.MinValue;
int max = int.MinValue;
foreach (int key in counts.Keys) {
if (counts[key] > max) {
max = counts[key];
result = key;
}
}
Console.WriteLine("The mode is: " + result);
As a beginner, this might not make too much sense, but it's worth providing a LINQ based solution.
x
.GroupBy(i => i) //place all identical values into groups
.OrderByDescending(g => g.Count()) //order groups by the size of the group desc
.Select(g => g.Key) //key of the group is representative of items in the group
.First() //first in the list is the most frequent (modal) value
Say, x array has items as below:
int[] x = { 1, 2, 6, 2, 3, 8, 2, 2, 3, 4, 5, 6, 4, 4, 4, 5, 39, 4, 5 };
a. Getting highest value:
int high = x.OrderByDescending(n => n).First();
b. Getting modal:
int mode = x.GroupBy(i => i) //Grouping same items
.OrderByDescending(g => g.Count()) //now getting frequency of a value
.Select(g => g.Key) //selecting key of the group
.FirstOrDefault(); //Finally, taking the most frequent value

How to calculate range of values from List<> with Linq?

I have a list of ordered numbers in C# and i want to calculate the min and max values that can take according to their secuencial value, with LINQ
The list is always ordered and never is empty.
For example:
My list object:
1060
1061
....
1089
1090
6368
6369
....
6383
6384
30165
30166
....
30214
30215
My expected results:
1060-1090
6368-6384
30165-30215
Thanks.
//Sample list of ordered integers
List<int> lst = new List<int>{101,102,103,104,106,107,108,111,112,114,120,121};
// find minimum element of each sub-sequence within the above list
var minBoundaries = lst.Where(i => !lst.Contains(i-1)).ToList();
// find maximum element of each sub-sequence within the above list
var maxBoundaries = lst.Where(i => !lst.Contains(i+1)).ToList();
//format minimum and maximum elements of each sub-sequence as per the sample output in the question
var result = new List<string>();
for(int i = 0; i < maxBoundaries.Count; i++)
result.Add(minBoundaries[i]+"-"+maxBoundaries[i]);
For problems like these, the Zip method is handy. This is what it does:
Applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
It can be used to pair the consecutive elements of a sequence, by ziping the sequence with itself.
var source = new List<int> { 1, 2, 3, 4, 5, 11, 12, 13, 21, 22 };
var gaps = source
.Zip(source.Skip(1), (n1, n2) => (n1, n2, gap: n2 - n1)) // Calculate the gaps
.Where(e => e.gap != 1) // Select non sequential pairs
.ToArray();
var gapsEx = gaps
.Prepend((n1: 0, n2: source.First(), gap: 0)) // Add the first element
.Append((n1: source.Last(), n2: 0, gap: 0)) // Add the last element
.ToArray();
var results = gapsEx
.Zip(gapsEx.Skip(1), (e1, e2) => (from: e1.n2, to: e2.n1)); // Pairwise gaps
Console.WriteLine($"Results: {String.Join(", ", results.Select(r => r.from + "-" + r.to))}");
Output:
Results: 1-5, 11-13, 21-22
Consider creating an extension method for IEnumerable<TSource>, so you can use it as if it was a LINQ function. See Extension Methods Demystified
Your example didn't handle several problems:
What if your input sequence is empty?
What if the input is not ordered?
What if you've got several time the same value: 1 2 3 3 3 3 4 5?
What if you have sub-sequences with only one contiguous number: 1 2 7 18 19?
So let's give a proper requirement:
Given an input sequence of integer numbers, create an output sequence of integer pairs, where the values are the first and the last number of a sequence of contiguous numbers in the input sequence.
Examples:
1060 1061 ... 1089 1090 6368 6369 ... 6384 30165 ... => [1060, 1090] [6369, 6384] [30165
2 3 4 5 17 18 19 4 5 6 7 1 2 3 4 5 => [2, 5] [17, 19] [4, 7] [1 5]
2 3 4 5 6 8 9 => [2, 5] [6, 6] [8, 9]
I'll return the sequence of pairs as a sequence of Tuple<int, int>. If desired you can create a dedicated class for this.
static IEnumerable<Tuple<int, int>> ToMinMaxTuples(this IEnumerable<int> source)
{
// TODO: source == null
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{
// there is at least one item in source
int min = enumerator.Current;
int max = min;
while (enumerator.MoveNext())
{
// there is another item in the sequence
if (enumerator.Current == max + 1)
{
// current is part of the current sequence, continue with next number
max = enumerator.Current;
}
else
{
// current is not part of the current sequence,
// it is the start of the next one
// yield return [min, max] as a Tuple:
yield return new Tuple<int, int>(min, max);
// start the next sequence:
min = enumerator.Current;
max = min;
}
}
}
}
usage:
IEnumerable<Tuple<int, int>> result = myInputList.ToMinMaxTuples();
Or in the middle of some big LINQ statement:
var result = Students
.Where(student => student.Country == "Republique Française")
.Select(student => student.Grade)
.ToMinMaxTuples()
.OrderBy(tuple => tuple.Item1)
.ThenBy(tuple => tuple.Item2);
If you implement a simple pair class then you can use the .Aggregate() LINQ method.
The pair class would be necessary since Tuples are immutable, but it can easily be constructed like so...
public class MinMaxPair<T>
{
public MinMaxPair(T min, T max)
{
Min = min;
Max = max;
}
public T Min;
public T Max;
}
Then with that in place, the .Aggregate() call would simply be
nums.Aggregate(
new List<MinMaxPair<int>>(),
(sets, next) =>
{
if (!sets.Any() || next - sets.Last().Max > 1)
{
sets.Add(new MinMaxPair<int>(next, next));
}
else
{
var minMax = sets.Last();
if (next < minMax.Min)
minMax.Min = next;
else
minMax.Max = next;
}
return sets;
});
Using a pair enhanced version of my Scan extension method, which is based on the APL scan operator that is similar to aggregate, but returns the intermediate results, I have created variable generalized grouping methods. Using GroupByPairsWhile I (had previously) created a GroupBySequential method for this sort of problem.
public static class IEnumerableExt {
// TKey combineFn((TKey Key, T Value) PrevKeyItem, T curItem):
// PrevKeyItem.Key = Previous Key
// PrevKeyItem.Value = Previous Item
// curItem = Current Item
// returns new Key
public static IEnumerable<(TKey Key, T Value)> ScanToPairs<T, TKey>(this IEnumerable<T> src, TKey seedKey, Func<(TKey Key, T Value), T, TKey> combineFn) {
using (var srce = src.GetEnumerator())
if (srce.MoveNext()) {
var prevkv = (seedKey, srce.Current);
while (srce.MoveNext()) {
yield return prevkv;
prevkv = (combineFn(prevkv, srce.Current), srce.Current);
}
yield return prevkv;
}
}
// bool testFn(T prevItem, T curItem)
// returns groups by runs of matching bool
public static IEnumerable<IGrouping<int, T>> GroupByPairsWhile<T>(this IEnumerable<T> src, Func<T, T, bool> testFn) =>
src.ScanToPairs(1, (kvp, cur) => testFn(kvp.Value, cur) ? kvp.Key : kvp.Key + 1)
.GroupBy(kvp => kvp.Key, kvp => kvp.Value);
public static IEnumerable<IGrouping<int, int>> GroupBySequential(this IEnumerable<int> src) => src.GroupByPairsWhile((prev, cur) => prev + 1 == cur);
}
With the extension method, your problem is simple:
var ans = src.GroupBySequential().Select(g => new { Min = g.Min(), Max = g.Max() });
This assumes the list is not ordered. If the list is known to be ordered, you could use First() and Last() instead of Min() and Max().
NOTE: The extension methods may seem complicated, but they provide the basis for multiple different types of grouping, including grouping by runs of equal items, grouping by generalized test functions, and with various seed and ending strategies for dealing with the first and last element when working in pairs.

How to improve my FindDuplicate classic algorithm

I have classic find duplicate algorithm like this:
int n = int.Parse(Console.ReadLine());
Console.WriteLine();
List<int> tempArr = new List<int>();
List<int> array = new List<int>();
for (int i = 0; i < n; i++)
{
Console.Write("input number {0}: ", i + 1);
tempArr.Add(int.Parse(Console.ReadLine()));
}
tempArr.Sort();
for (int i = 0; i < n; i++)
{
for (int j = i+1; j < n; j++)
{
if (tempArr[i] == tempArr[j])
{
array.Add(tempArr[i]);
}
}
}
Everything work's okay, but if i have just two duplicate numbers like (1,2,2,3,4,5) how can i add them both to List<int> **array** with one clean shot at the loop ?
Instead of lists you could use some kind of data structure that have a better search capability (hash tables or binary trees, for example). Even if you have just one duplicate, the problem is that you need to check if you have already added the element in the list, so the key operation in your algorithm is the search. The faster you perform the search, the faster the algorithm will be. Using binary search, which is the fastest way to search, you get O(nlogn) (you perform n searches of O(logn)).
An even better way to do this is to have some kind of array that has the same size as your input range and "tick" each value that you already have. This search runs in constant time, but gets inefficient if you have a large range of input.
You can use distinct:
array = tempArr.Distinct().ToList();
Distinct isn't in linear time, if that's what you're looking for ("one clean shot"). If you know more about the input you might be able to find a way to do this in linear time. For example, if you know if the integers you take are in a certain range.
To extract all the duplicates you can use Linq:
List<int> tempList = new List<int>() { 1, 2, 2, 3, 4, 5 };
// array == [2, 2]
List<int> array = tempList
.GroupBy(x => x)
.Where(x => x.Count() > 1)
.SelectMany(x => Enumerable.Repeat(x.Key, x.Count()))
.ToList();

Given a list of length n select k random elements using C#

I found this post:
Efficiently selecting a set of random elements from a linked list
But this means that in order to approach true randomness in the sample I have to iterate over all elements, throw them in memory with a random number, and then sort. I have a very large set of items here (millions) - is there a more efficient approach to this problem?
I would suggest simply shuffling elements as if you were writing a modified Fisher-Yates shuffle, but only bother shuffling the first k elements. For example:
public static void PartialShuffle<T>(IList<T> source, int count, Random random)
{
for (int i = 0; i < count; i++)
{
// Pick a random element out of the remaining elements,
// and swap it into place.
int index = i + random.Next(source.Count - i);
T tmp = source[index];
source[index] = source[i];
source[i] = tmp;
}
}
After calling this method, the first count elements will be randomly picked elements from the original list.
Note that I've specified the Random as a parameter, so that you can use the same one repeatedly. Be careful about threading though - see my article on randomness for more information.
Take a look at this extension method http://extensionmethod.net/csharp/ienumerable-t/shuffle. You could add Skip() Take() type to page the values out the final list.
If the elements can be in memory, put them in memory first
List<Element> elements = dbContext.Select<Element>();
Now you know the number of elements. Create a set of unique indexes.
var random = new Random();
var indexes = new HashSet<int>();
while (indexes.Count < k) {
indexes.Add(random.Next(elements.Count));
}
Now you can read the elements from the list
var randomElements = indexes.Select(i => elements[i]);
I assume that the DB contains unique elements. If this is not the case, you will have to create a HashSet<Elements> instead or to append .Distinct() when querying from the DB.
UPDATE
As Patricia Shanahan says, this method will work well if k is small compared to n. If it is not the case, I suggest selecting a set n - k indexes to be excluded
var random = new Random();
var indexes = new HashSet<int>();
IEnumerable<Element> randomElements;
if (k <= elements.Count / 2) {
while (indexes.Count < k) {
indexes.Add(random.Next(elements.Count));
}
randomElements = indexes.Select(i => elements[i]);
} else {
while (indexes.Count < elements.Count - k) {
indexes.Add(random.Next(elements.Count));
}
randomElements = elements
.Select((e,i) => indexes.Contains(i) ? null : elements[i])
.Where(e => e != null);
}

How to merge 2 sorted listed into one shuffled list while keeping internal order in c#

I want to generate a shuffled merged list that will keep the internal order of the lists.
For example:
list A: 11 22 33
list B: 6 7 8
valid result: 11 22 6 33 7 8
invalid result: 22 11 7 6 33 8
Just randomly select a list (e.g. generate a random number between 0 and 1, if < 0.5 list A, otherwise list B) and then take the element from that list and add it to you new list. Repeat until you have no elements left in each list.
Generate A.Length random integers in the interval [0, B.Length). Sort the random numbers, then iterate i from 0..A.Length adding A[i] to into position r[i]+i in B. The +i is because you're shifting the original values in B to the right as you insert values from A.
This will be as random as your RNG.
None of the answers provided in this page work if you need the outputs to be uniformly distributed.
To illustrate my examples, assume we are merging two lists A=[1,2,3], B=[a,b,c]
In the approach mentioned in most answers (i.e. merging two lists a la mergesort, but choosing a list head randomly each time), the output [1 a 2 b 3 c] is far less likely than [1 2 3 a b c]. Intuitively, this happens because when you run out of elements in a list, then the elements on the other list are appended at the end. Because of that, the probability for the first case is 0.5*0.5*0.5 = 0.5^3 = 0.125, but in the second case, there are more random random events, since a random head has to be picked 5 times instead of just 3, leaving us with a probability of 0.5^5 = 0.03125. An empirical evaluation also easily validates these results.
The answer suggested by #marcog is almost correct. However, there is an issue where the distribution of r is not uniform after sorting it. This happens because original lists [0,1,2], [2,1,0], [2,1,0] all get sorted into [0,1,2], making this sorted r more likely than, for example, [0,0,0] for which there is only one possibility.
There is a clever way of generating the list r in such a way that it is uniformly distributed, as seen in this Math StackExchange question: https://math.stackexchange.com/questions/3218854/randomly-generate-a-sorted-set-with-uniform-distribution
To summarize the answer to that question, you must sample |B| elements (uniformly at random, and without repetition) from the set {0,1,..|A|+|B|-1}, sort the result and then subtract its index to each element in this new list. The result is the list r that can be used in replacement at #marcog's answer.
Original Answer:
static IEnumerable<T> MergeShuffle<T>(IEnumerable<T> lista, IEnumerable<T> listb)
{
var first = lista.GetEnumerator();
var second = listb.GetEnumerator();
var rand = new Random();
bool exhaustedA = false;
bool exhaustedB = false;
while (!(exhaustedA && exhaustedB))
{
bool found = false;
if (!exhaustedB && (exhaustedA || rand.Next(0, 2) == 0))
{
exhaustedB = !(found = second.MoveNext());
if (found)
yield return second.Current;
}
if (!found && !exhaustedA)
{
exhaustedA = !(found = first.MoveNext());
if (found)
yield return first.Current;
}
}
}
Second answer based on marcog's answer
static IEnumerable<T> MergeShuffle<T>(IEnumerable<T> lista, IEnumerable<T> listb)
{
int total = lista.Count() + listb.Count();
var random = new Random();
var indexes = Enumerable.Range(0, total-1)
.OrderBy(_=>random.NextDouble())
.Take(lista.Count())
.OrderBy(x=>x)
.ToList();
var first = lista.GetEnumerator();
var second = listb.GetEnumerator();
for (int i = 0; i < total; i++)
if (indexes.Contains(i))
{
first.MoveNext();
yield return first.Current;
}
else
{
second.MoveNext();
yield return second.Current;
}
}
Rather than generating a list of indices, this can be done by adjusting the probabilities based on the number of elements left in each list. On each iteration, A will have A_size elements remaining, and B will have B_size elements remaining. Choose a random number R from 1..(A_size + B_size). If R <= A_size, then use an element from A as the next element in the output. Otherwise use an element from B.
int A[] = {11, 22, 33}, A_pos = 0, A_remaining = 3;
int B[] = {6, 7, 8}, B_pos = 0, B_remaining = 3;
while (A_remaining || B_remaining) {
int r = rand() % (A_remaining + B_remaining);
if (r < A_remaining) {
printf("%d ", A[A_pos++]);
A_remaining--;
} else {
printf("%d ", B[B_pos++]);
B_remaining--;
}
}
printf("\n");
As a list gets smaller, the probability an element gets chosen from it will decrease.
This can be scaled to multiple lists. For example, given lists A, B, and C with sizes A_size, B_size, and C_size, choose R in 1..(A_size+B_size+C_size). If R <= A_size, use an element from A. Otherwise, if R <= A_size+B_size use an element from B. Otherwise C.
Here is a solution that ensures a uniformly distributed output, and is easy to reason why. The idea is first to generate a list of tokens, where each token represent an element of a specific list, but not a specific element. For example for two lists having 3 elements each, we generate this list of tokens: 0, 0, 0, 1, 1, 1. Then we shuffle the tokens. Finally we yield an element for each token, selecting the next element from the corresponding original list.
public static IEnumerable<T> MergeShufflePreservingOrder<T>(
params IEnumerable<T>[] sources)
{
var random = new Random();
var queues = sources
.Select(source => new Queue<T>(source))
.ToArray();
var tokens = queues
.SelectMany((queue, i) => Enumerable.Repeat(i, queue.Count))
.ToArray();
Shuffle(tokens);
return tokens.Select(token => queues[token].Dequeue());
void Shuffle(int[] array)
{
for (int i = 0; i < array.Length; i++)
{
int j = random.Next(i, array.Length);
if (i == j) continue;
if (array[i] == array[j]) continue;
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
Usage example:
var list1 = "ABCDEFGHIJKL".ToCharArray();
var list2 = "abcd".ToCharArray();
var list3 = "#".ToCharArray();
var merged = MergeShufflePreservingOrder(list1, list2, list3);
Console.WriteLine(String.Join("", merged));
Output:
ABCDaEFGHIb#cJKLd
This might be easier, assuming you have a list of three values in order that match 3 values in another table.
You can also sequence with the identity using identity (1,2)
Create TABLE #tmp1 (ID int identity(1,1),firstvalue char(2),secondvalue char(2))
Create TABLE #tmp2 (ID int identity(1,1),firstvalue char(2),secondvalue char(2))
Insert into #tmp1(firstvalue,secondvalue) Select firstvalue,null secondvalue from firsttable
Insert into #tmp2(firstvalue,secondvalue) Select null firstvalue,secondvalue from secondtable
Select a.firstvalue,b.secondvalue from #tmp1 a join #tmp2 b on a.id=b.id
DROP TABLE #tmp1
DROP TABLE #tmp2

Categories