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.
Related
Hello is there any efficient method implemented already to get the functionality of Haskell Data.List.span?
span :: (a -> Bool) -> [a] -> ([a], [a])
Basically given a list and a predicate i want to split the list in two after the first occurence of a false predicate.The elements after the pivot element that tests False may or may not respect the predicate , but I do not care.
List: [1,2,3,1,2,3]
Predicate: x<3
Span: `span (x<3) [1,2,3,1,2,3]` => `([1,2],[3,1,2,3])`
Update
I do not care of the elements after the first false predicate.I just want to split the list at the first occurence of False predicate. The sequence can be True after the first False predicate but I still want to split it.
If you are happy with using lists, then you can make a single pass through the source list to create two new lists, like so:
public static (List<T> part1, List<T> part2) SplitListBy<T>(List<T> source, Predicate<T> splitWhen)
{
var part1 = new List<T>();
int i;
for (i = 0; i < source.Count && !splitWhen(source[i]); ++i)
part1.Add(source[i]);
var part2 = source.GetRange(i, source.Count - i);
return (part1, part2);
}
This should be extremely performant. Note that this uses a tuple to return the two lists, which requires C# 7 or later. If you can't use c# 7+, you'll have to change the code to use an out parameter to return one of the lists.
Test code:
var list = new List<int>{ 1, 2, 3, 1, 2, 3 };
var (part1, part2) = SplitListBy(list, item => item >= 3);
Console.WriteLine(string.Join(", ", part1));
Console.WriteLine(string.Join(", ", part2));
Output:
1, 2
3, 1, 2, 3
If you don't need two new lists, but just want to use the original list for one part and a single new list for the other part, you can do it like this:
public static List<T> SplitListBy<T>(List<T> source, Predicate<T> splitWhen)
{
int i;
for (i = 0; i < source.Count && !splitWhen(source[i]); ++i)
;
var part2 = source.GetRange(i, source.Count - i);
source.RemoveRange(i, source.Count - i);
return part2;
}
Test code for this is very similar:
var list = new List<int>{ 1, 2, 3, 1, 2, 3 };
var part2 = SplitListBy(list, item => item >= 3);
Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", part2));
(Output is the same as the other test code.)
You could make use of TakeWhile and Skip:
public static IEnumerable<IEnumerable<T>> SplitWhen<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
var first = enumerable.TakeWhile(predicate);
yield return first;
var second = enumerable.Skip(first.Count());
yield return second;
}
Update
To avoid multiple iterations, and not requiring the use of a list or array:
public static IEnumerable<IEnumerable<T>> SplitWhen<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
yield return enumerable.TakeWhile(predicate);
yield return enumerable.TakeAfter(predicate);
}
public static IEnumerable<T> TakeAfter<T>(this IEnumerable<T> enumerable, Func<T, bool> predicate)
{
bool yielding = false;
foreach (T item in enumerable)
{
if (yielding = yielding || !predicate(item))
{
yield return item;
}
}
}
At the time that I'm writing this answer, I don't think that any of the other answers faithfully replicate Haskell's span function. That's okay, you may actually be looking for something else, but I wanted to add this for completion's sake.
First, you can't necessarily assume that span only iterates over the input list once. It's difficult to reason about Haskell's run-time behaviour because of its lazy evaluation, but consider this list:
xs = [trace "one" 1, trace "two" 2, trace "three" 3,
trace "one" 1, trace "two" 2, trace "three" 3]
Here I've deliberately used trace from Debug.Trace so that we can observe what's going on. Specifically, I want to point your attention to what happens if you iterate over the lists independently, as one would probably do in 'real' code:
Prelude Data.List Debug.Trace> (l, r) = span (< 3) xs
Prelude Data.List Debug.Trace> l
one
[1two
,2three
]
Iterating over the first list stops at the first value that evaluates to False, so that's fine and efficient. That's not the case, however, when you print the second list:
Prelude Data.List Debug.Trace> r
one
two
three
[3,one
1,two
2,three
3]
Notice that while it only prints [3, 1, 2, 3], it iterates over the entire list. How could it do otherwise? It's a function. It doesn't maintain a bookmark over how far it's already iterated the list.
On the other hand, the function does handle infinite lists:
Prelude Data.List> take 10 $ fst $ span (< 3) $ repeat 1
[1,1,1,1,1,1,1,1,1,1]
Prelude Data.List> take 10 $ fst $ span (< 3) $ repeat 3
[]
Prelude Data.List> take 10 $ snd $ span (< 3) $ repeat 3
[3,3,3,3,3,3,3,3,3,3]
As far as I can tell, few of the other answers (as I'm writing this) handle infinite lists.
In C#, lazily evaluated lists are modelled with IEnumerable<T>, so the best I've been able to come up with is this:
public static (IEnumerable<T>, IEnumerable<T>) Span<T>(
this IEnumerable<T> source,
Func<T, bool> pred)
{
return (source.TakeWhile(pred), source.SkipWhile(pred));
}
which, admittedly, is hardly above the Fairbairn threshold. It does, however, handle infinite sequences in the same way as span does:
> var (left, right) = new[] { 1, 2, 3, 1, 2, 3 }.Span(x => x < 3);
> left
TakeWhileIterator { 1, 2 }
> right
SkipWhileIterator { 3, 1, 2, 3 }
> var (left, right) = 1.RepeatInfinite().Span(x => x < 3);
> left.Take(10)
TakeIterator { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
> var (left, right) = 3.RepeatInfinite().Span(x => x < 3);
> right.Take(10)
TakeIterator { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }
> left.Take(10)
TakeIterator { }
I don't think there is a native .NET Framework or .NET Core method that does this, so you'll probably have to write your own. Here is my extension method implementation of this:
public static Tuple<IEnumerable<T>, IEnumerable<T>> SplitWhen<T>(this IEnumerable<T> self, Func<T, bool> func)
{
// Enumerate self to an array so we don't do it multiple times
var enumerable = self as T[] ?? self.ToArray();
var matching = enumerable.TakeWhile(func).ToArray();
var notMatching = enumerable.Skip(matching.Length);
return new Tuple<IEnumerable<T>, IEnumerable<T>>(matching, notMatching);
}
This method will return a tuple with tuple.Item1 being the part of the list that matches the predicate, and tuple.Item2 being the rest of the list.
This method needs to be declared in a separate static class as it is an extension method for IEnumerable<T>. You can also use Tuple construction/ deconstruction if you want to name Item1 and Item2 something different
the simplest way to use ToLookup
example
var listInt = new List<int>{1, 2, 3, 4, 5, 6};
var result = listInt.ToLookup(x => x > 3);
Result
[[1,2,3], [4,5,6]]
Edit
var listInt = new List<int> { 1, 2, 3, 1, 2, 3 };
Create an extension method
public static IEnumerable<T> TakeUntil<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
foreach (var item in source)
{
if (!predicate(item))
break;
yield return item;
}
}
and call it
var first = listInt.TakeUntil(x => x < 3);
var second = listInt.Skip(first.Count());
Result
first = [1,2]
second = [3, 1, 2, 3]
I believe you are looking for a c# IEnumerable. You could write for example
IEnumerable<int> list = new List<int> { 1,2,3,4,5,6};
var list1 = list.Where(x=>x>3); //deferred execution
var list2 = list.Where(x=>x<=3); //deferred execution
I have accepted #Matthew Watson solution.Though i will also post a little modified version using the Span and ReadOnlyMemory
public static (IEnumerable<T>first,IEnumerable<T> second) Span<T>(this ReadOnlyMemory<T> original,Func<T,bool> predicate) {
List<T> list = new List<T>();
int splitIndex = 0;
for (int i = 0; i < original.Length && !predicate(original.Span[i]); i++) {
list.Add(original.Span[splitIndex=i]);
}
var part2 = original.Slice(splitIndex);
return (list, part2.ToArray());
}
This question already has answers here:
How to check if list contains another list in same order
(2 answers)
Closed 4 years ago.
Is there any elegant way in c# to check whether a List<T> contains a sub-List<T> similar to string.Contains(string)?
Let's say e.g. I want to test for example whether List A is contained in List B
List<int> A = new List<int>{ 1, 2, 3, 4, 3, 4, 5 };
List<int> B = new List<int>{ 3, 4, 5 };
important is that all elements have to match in exactly that order.
I know I could possibly do something like
bool Contains(List<Sampletype> source, List<Sampletype> sample)
{
// sample has to be smaller or equal length
if (sample.Count > source.Count) return false;
// doesn't even contain first element
if (!source.Contains(sample[0])) return false;
// get possible starts
// see https://stackoverflow.com/a/10443540/7111561
int[] possibleStartIndexes = source.Select((b, i) => b == sample[0] ? i : -1).Where(i => i != -1).ToArray();
foreach (int possibleStartIndex in possibleStartIndexes)
{
// start is too late -> can't match
if (possibleStartIndex + sample.Count - 1 > source.Count - 1) return false;
for (int index = possibleStartIndex; index < possibleStartIndex + sample.Count; index++)
{
// if one element does not match the whole sample doesn't match
if (source[index] != sample[index]) return false;
}
// if this is reached all elements of the sample matched
Debug.Log("Match found starting at index " + possibleStartIndex);
return true;
}
return false;
}
But I hope there is a better way to do so.
Here's a oneliner:
var result = A.Select(a => $"{a}").Aggregate((c, n) => $"{c};{n}").Contains(B.Select(b => $"{b}").Aggregate((c, n) => $"{c};{n}"));
It basically creates a string from each list, and checks whether the A string contains the B string. This way you won't just get a method like string.Contains, you actually get to use just that.
EDIT
Added separator to the string aggregations, as {1, 2, 3} would result in the same string as {1, 23}
EDIT 2
Re-adding my first approach which identifies if list B is present in list A, perhaps scattered, but still ordered:
var result = B.Intersect(A).SequenceEqual(B)
Essentially you want to slide over A and check each element of that window with the B. The last part is actually SequenceEqual and I do recommend to use it but this is just an alternative to explain the point:
bool equal = Enumerable.Range(0, A.Count() - B.Count() + 1)
.Select(i => A.Skip(i).Take(B.Count))
.Any(w => w.Select((item, i) => item.Equals(B[i])).All(item => item));
suppose I have this query :
int[] Numbers= new int[5]{5,2,3,4,5};
var query = from a in Numbers
where a== Numbers.Max (n => n) //notice MAX he should also get his value somehow
select a;
foreach (var element in query)
Console.WriteLine (element);
How many times does Numbers is enumerated when running the foreach ?
how can I test it ( I mean , writing a code which tells me the number of iterations)
It will be iterated 6 times. Once for the Where and once per element for the Max.
The code to demonstrate this:
private static int count = 0;
public static IEnumerable<int> Regurgitate(IEnumerable<int> source)
{
count++;
Console.WriteLine("Iterated sequence {0} times", count);
foreach (int i in source)
yield return i;
}
int[] Numbers = new int[5] { 5, 2, 3, 4, 5 };
IEnumerable<int> sequence = Regurgitate(Numbers);
var query = from a in sequence
where a == sequence.Max(n => n)
select a;
It will print "Iterated sequence 6 times".
We could make a more general purpose wrapper that is more flexible, if you're planning to use this to experiment with other cases:
public class EnumerableWrapper<T> : IEnumerable<T>
{
private IEnumerable<T> source;
public EnumerableWrapper(IEnumerable<T> source)
{
this.source = source;
}
public int IterationsStarted { get; private set; }
public int NumMoveNexts { get; private set; }
public int IterationsFinished { get; private set; }
public IEnumerator<T> GetEnumerator()
{
IterationsStarted++;
foreach (T item in source)
{
NumMoveNexts++;
yield return item;
}
IterationsFinished++;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override string ToString()
{
return string.Format(
#"Iterations Started: {0}
Iterations Finished: {1}
Number of move next calls: {2}"
, IterationsStarted, IterationsFinished, NumMoveNexts);
}
}
This has several advantages over the other function:
It records both the number of iterations started, the number of iterations that were completed, and the total number of times all of the sequences were incremented.
You can create different instances to wrap different underlying sequences, thus allowing you to inspect multiple sequences per program, instead of just one when using a static variable.
Here is how you can estimate a quick count of the number of times the collection is enumerated: wrap your collection in a CountedEnum<T>, and increment counter on each yield return, like this --
static int counter = 0;
public static IEnumerable<T> CountedEnum<T>(IEnumerable<T> ee) {
foreach (var e in ee) {
counter++;
yield return e;
}
}
Then change your array declaration to this,
var Numbers= CountedEnum(new int[5]{5,2,3,4,5});
run your query, and print the counter. For your query, the code prints 30 (link to ideone), meaning that your collection of five items has been enumerated six times.
Here is how you can check the count
void Main()
{
var Numbers= new int[5]{5,2,3,4,5}.Select(n=>
{
Console.Write(n);
return n;
});
var query = from a in Numbers
where a== Numbers.Max (n => n)
select a;
foreach (var element in query)
{
var v = element;
}
}
Here is output
5 5 2 3 4 5 2 5 2 3 4 5 3 5 2 3 4 5 4 5 2 3 4 5 5 5 2 3 4 5
The number of iteration has to be equal to query.Count().
So to the count of the elements in the result of the first query.
If you're asking about something else, please clarify.
EDIT
After clarification:
if you're searching for total count of the iteration in the code provided, there will be 7 iterations (for this concrete case).
var query = from a in Numbers
where a== Numbers.Max (n => n) //5 iterations to find MAX among 5 elements
select a;
and
foreach (var element in query)
Console.WriteLine (element); //2 iterations over resulting collection(in this question)
How many times does Numbers is enumerated when running the foreach
Loosely speaking, your code is morally equivalent to:
foreach(int a in Numbers)
{
// 1. I've gotten rid of the unnecessary identity lambda.
// 2. Note that Max works by enumerating the entire source.
var max = Numbers.Max();
if(a == max)
Console.WriteLine(a);
}
So we enumerate the following times:
One enumeration of the sequence for the outer loop (1).
One enumeration of the sequence for each of its members (Count).
So in total, we enumerate Count + 1 times.
You could bring this down to 2 by hoisting the Max query outside the loop by introducing a local.
how can I test it ( I mean , writing a code which tells me the number
of iterations)
This wouldn't be easy with a raw array. But you could write your own enumerable implementation (that perhaps wrapped an array) and add some instrumentation to the GetEnumerator method. Or if you want to go deeper, go the whole hog and write a custom enumerator with instrumentation on MoveNext and Current as well.
Count via public property also yields 6.
private static int ncount = 0;
private int[] numbers= new int[5]{5,2,3,4,5};
public int[] Numbers
{
get
{
ncount++;
Debug.WriteLine("Numbers Get " + ncount.ToString());
return numbers;
}
}
This brings the count down to 2.
Makes sense but I would not have thought of it.
int nmax = Numbers.Max(n => n);
var query = from a in Numbers
where a == nmax //notice MAX he should also get his value somehow
//where a == Numbers.Max(n => n) //notice MAX he should also get his value somehow
select a;
It will be iterated 6 times. Once for the Where and once per element for the Max.
Define and initialize a count variable outside the foreach loop and increment the count variable as count++ inside the loop to get the number of times of enumeration.
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.
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