Change array according to the sequence - c#

I have some Image sliders, and I wanted to change the sequence of the image slider. Current sequence is set from a database field (fetch the set of sequence numbers from the database and show it).
Now, I want to change the sequence number.Lets say,
My slider sequence is 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 & I need to change the 4th position slider to 8th position and after that my slider number sequence is 1, 2, 3, 5, 6, 7, 4, 8, 9, 10.
Here is an image to make it easy to understand
I have a int array with current sequence,
int[] currentSequence = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
MyCode:
int[] currentSequence = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var currentPosition = iproductrepositroy.GetSingle(x => x.ProductName.Equals(ProductName)).ProductSequence;// 4th position
var expectedPosition = ChangeSequence;// 8th position
if (currentPosition < expectedPosition)//right shift -->
{
int i = 0;
for (i = (int)currentPosition + 1; i < expectedPosition; i++)
{
// I wanted to know how to change the above array here
}
}
else//left shift <--
{
int i;
for (i = (int)currentPosition - 1; i > expectedPosition; i--)
{
}
}

This might be easier for you to do in a List:
class Program
{
static void Main(string[] args)
{
int currentPosition = 3;
int expectedPosition = 7;
int adjust = (currentPosition < expectedPosition) ? 1 : 0;
List<int> list = new List<int> { 1,2,3,4,5,6,7,8,9,10};
var item = list[currentPosition];
list.RemoveAt(currentPosition);
list.Insert(expectedPosition - adjust , item); //Insert position may be one less at the moment, so use calculated adjustment
foreach (int i in list)
{
Console.WriteLine(i.ToString());
}
var discard = Console.ReadKey();
}
}

Unless I've misunderstood your requirements then this is the simplest way to do the reordering:
var currentSequence = new [] { 1,2,3,4,5,6,7,8,9,10 };
var reordering = new [] { 1,2,3,5,6,7,4,8,9,10 };
var reorderedSequence =
reordering
.Select(r => currentSequence[r - 1])
.ToArray();
To show that this works, try it with this:
var currentSequence = new [] { "A","B","C","D","E","F","G","H","I","J" };
That gives back:
{ "A", "B", "C", "E", "F", "G", "D", "H", "I", "J" }

Related

Take n elements. If at end start from begining

How can I take n elements from a m elements collection so that if I run out of elements it starts from the beginning?
List<int> list = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<int> newList = list.Skip(9).Take(2).ToList();
List<int> expected = new List(){10,1};
CollectionAssert.AreEqual(expected, newList);
How can I get the expected list?
I'm looking for a CircularTake() function or something in that direction.
use an extension method to circular repeat the enumerable
public static IEnumerable<T> Circular<T>( this IEnumerable<T> source )
{
while (true)
foreach (var item in source)
yield return item;
}
and you can use your code
List<int> list = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<int> newList = list.Circular().Skip(9).Take(2).ToList();
.net fiddle example
You don't need to track the overflow because we can use the % modulus operator (which returns the remainder from an integer division) to continually loop through a range of indexes, and it will always return a valid index in the collection, wrapping back to 0 when it gets to the end (and this will work for multiple wraps around the end of the list):
List<int> list = new List<int> {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
List<int> newList = new List<int>();
for (int skip = 9, take = 2; take > 0; skip++, take--)
{
newList.Add(list[skip % list.Count]);
}
Result:
// newList == { 10, 1 }
This could be extracted into an extension method:
public static List<T> SkipTakeWrap<T>(this List<T> source, int skip, int take)
{
var newList = new List<T>();
while (take > 0)
{
newList.Add(source[skip % source.Count]);
skip++;
take--;
}
return newList;
}
And then it could be called like:
List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> newList = list.SkipTakeWrap(9, 2);
you may need to do something like this
var start = 9;
var amount = 2;
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
List<int> listOverflow = list.ToList();
var overflow = (start + amount) - list.Count;
if (overflow > 0)
for (var i = 0; i < overflow; i++)
listOverflow.AddRange(list.ToList());
var newList = listOverflow.Skip(start).Take(amount).ToList();
My take on a CircularTake extension.
public static IEnumerable<T> CircularTake<T>(this IReadOnlyList<T> source, int count)
{
return Enumerable.Range(0, count).Select(i => source[i % source.Count]);
}
int overflow = take - (elements.Count - skip);
if(overflow > 0)
{
results.AddRange(elements.Skip(skip).Take(take - overflow));
results.AddRange(elements.Take(overflow));
}
If there is a possiblity that there are more than one circular iterations, e.g. from 3 elements, take 10 or more, then you can apply this logic in a recursive function.

Check if all elements from one array are in the second array c#

How can I check if all the elements from one array are in another array? I have a 2d array with 3 arrays in it,and I want to check all of those 3 arrays if they have all the elements from allnumbers. array1=allnumbers ? array2=allnumbers ? array1=allnumber2 ? I need to return true if at least one contains all the elements from allnumbers. I have the code bellow,but I need it not to contain more than 3 control flow statements.
// int[,][] array = {array1, array2, array3}
static bool CheckLine(int[,][] array)
{
const int maxL = 9;
bool result = false;
int[] allnumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (var singlearray in array)
{
int[] arr = singlearray;
int p = 0;
foreach (var num in allnumbers)
{
foreach (var arraynumber in singlearray)
{
if (arraynumber == num)
{
p++;
}
}
if (p == maxL)
{
result = true;
break;
}
}
}
return result;
}
If the values in your array are unique, and you don't care about the order they're in, this is a job for HashSet. (In other words, if your arrays contain sets of numbers you can treat them as sets.) Here's the basic outline of comparing sets.
var allnumbersSet = new HashSet<int>(allnumbers);
var allnumbers2Set= new HashSet<int>(allnumbers2);
if (allnumbersSet.IsSupersetOf(allnumbers2Set)) {
/* everything in allnumbers2 is also in allnumbers1 */
}
The people who put together DotNet did a really good job creating and optimizing those collection classes; you can use them with confidence to get good performance.
It seems, that you have two-dimensional jagged array. You can simplify your code by using Except and check the difference between allnumbers array and single row at every loop iteration.
static bool CheckLine(int[,][] array)
{
int[] allnumbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (var singlearray in array)
{
var diff = allnumbers.Except(singlearray);
if (!diff.Any())
{
return true;
}
}
return false;
}
If there is no elements in a difference, it'll mean that single item from source 2D array has all elements from allnumbers array.
Example of the usage
var array = new int[2, 2][];
array[0, 0] = new[] { 1, 2, 8 };
array[0, 1] = new[] { 3, 4, 5, 6 };
array[1, 1] = new[] { 3, 2, 1, 4, 5, 7, 6, 10, 9, 8 };
array[1, 0] = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
CheckLine(array);
The last two items satisfy the condition, execution will break and return true for { 3, 2, 1, 4, 5, 7, 6, 10, 9, 8 } array. Also don't forget to add using System.Linq directive at the top of file
Thank you for your help. I forgot to mention that I can use only "using System;"

What sort orders items by alternating between placing an item at the start or end of the list?

I have an ordered list, largest to smallest.
{ 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }
I want a list like this
{ 10, 8, 6, 4, 2, 1, 3, 5, 7, 9 }
If you can see, the new order is, first by each odd index ascending, then by each even index descending.
The idea is that each half of the list has roughly the same weight. e.g
{ 10, 8, 6, 4, 2 } = 30
{ 1, 3, 5, 7, 9 } = 25
The title is the best I can explain in a sentence what I'm looking for which is why I had trouble finding the answer from Google.
Here is my go in C#. I'll welcome any comment on my attempt but I'm only looking of the algorithms name, if it has one.
var firstHalf = new List<string>();
var secondHalf = new List<string>();
for (int i = 0; i < originalList.Count; i++)
{
if (i % 2 == 1)
{
firstHalf.Add(originalList[i]);
}
else
{
secondHalf.Add(originalList[i]);
}
}
secondHalf.Reverse();
var finalList = new List<string>(firstHalf);
finalList.AddRange(secondHalf);
This might not be the most efficient way, but it's easy:
var yourlist = originalList.Where(i => i % 2 == 0)
.OrderBy(i => i)
.Concat(originalList.Where(i => i % 2 != 0)
.OrderByDescending(i => i))
.ToList();

What's the best way to apply a "Join" method generically similar to how String.Join(...) works?

If I have a string array, for example: var array = new[] { "the", "cat", "in", "the", "hat" }, and I want to join them with a space between each word I can simply call String.Join(" ", array).
But, say I had an array of integer arrays (just like I can have an array of character arrays). I want to combine them into one large array (flatten them), but at the same time insert a value between each array.
var arrays = new[] { new[] { 1, 2, 3 }, new[] { 4, 5, 6 }, new { 7, 8, 9 }};
var result = SomeJoin(0, arrays); // result = { 1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9 }
I wrote something up, but it is very ugly, and I'm sure that there is a better, cleaner way. Maybe more efficient?
var result = new int[arrays.Sum(a => a.Length) + arrays.Length - 1];
int offset = 0;
foreach (var array in arrays)
{
Buffer.BlockCopy(array, 0, result, offset, b.Length);
offset += array.Length;
if (offset < result.Length)
{
result[offset++] = 0;
}
}
Perhaps this is the most efficient? I don't know... just seeing if there is a better way. I thought maybe LINQ would solve this, but sadly I don't see anything that is what I need.
You can generically "join" sequences via:
public static IEnumerable<T> Join<T>(T separator, IEnumerable<IEnumerable<T>> items)
{
var sep = new[] {item};
var first = items.FirstOrDefault();
if (first == null)
return Enumerable.Empty<T>();
else
return first.Concat(items.Skip(1).SelectMany(i => sep.Concat(i)));
}
This works with your code:
var arrays = new[] { new[] { 1, 2, 3 }, new[] { 4, 5, 6 }, new { 7, 8, 9 }};
var result = Join(0, arrays); // result = { 1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9 }
The advantage here is that this will work with any IEnumerable<IEnumerable<T>>, and isn't restricted to lists or arrays. Note that this will insert a separate in between two empty sequences, but that behavior could be modified if desired.
public T[] SomeJoin<T>(T a, T[][] arrays){
return arrays.SelectMany((x,i)=> i == arrays.Length-1 ? x : x.Concat(new[]{a}))
.ToArray();
}
NOTE: The code works seamlessly because of using Array, otherwise we may lose some performance cost to get the Count of the input collection.
This may not be the most efficient, but it is quite extensible:
public static IEnumerable<T> Join<T>(this IEnumerable<IEnumerable<T>> source, T separator)
{
bool firstTime = true;
foreach (var collection in source)
{
if (!firstTime)
yield return separator;
foreach (var value in collection)
yield return value;
firstTime = false;
}
}
...
var arrays = new[] { new[] { 1, 2, 3 }, new[] { 4, 5, 6 }, new[] { 7, 8, 9 }};
var result = arrays.Join(0).ToArray();
// result = { 1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9 }

Align multiple sorted lists

If I have, for example the following List<int>s
{ 1, 2, 3, 4 } //list1
{ 2, 3, 5, 6 } //list2
...
{ 3, 4, 5 } //listN
What is the best way to retrieve the following corresponding List<int?>s?
{ 1, 2, 3, 4, null, null } //list1
{ null, 2, 3, null, 5, 6 } //list2
...
{ null, null, 3, 4, 5, null } //listN
I'm posting the solution we discussed in chat. I had an unoptimized version using Linq for all things loopy/filtering:
http://ideone.com/H4gCoE (live demo)
However, I suspect it won't be too performant because of all the enumerator classes created, and the collections being instantiated/modified along the way.
So I took the time to optimize it into handwritten loops with an administration to keep track of active iterators instead of modifying the iters collection. Here it is:
See http://ideone.com/FuZIDy for full live demo.
Note I assume the lists are pre-ordered by DefaultComparer<T>, since I use Linq'sMin() extension method without a custom comparer
public static IEnumerable<IEnumerable<T>> AlignSequences<T>(this IEnumerable<IEnumerable<T>> sequences)
{
var iters = sequences
.Select((s, index) => new { active=true, index, enumerator = s.GetEnumerator() })
.ToArray();
var isActive = iters.Select(it => it.enumerator.MoveNext()).ToArray();
var numactive = isActive.Count(flag => flag);
try
{
while (numactive > 0)
{
T min = iters
.Where(it => isActive[it.index])
.Min(it => it.enumerator.Current);
var row = new T[iters.Count()];
for (int j = 0; j < isActive.Length; j++)
{
if (!isActive[j] || !Equals(iters[j].enumerator.Current, min))
continue;
row[j] = min;
if (!iters[j].enumerator.MoveNext())
{
isActive[j] = false;
numactive -= 1;
}
}
yield return row;
}
}
finally
{
foreach (var iter in iters) iter.enumerator.Dispose();
}
}
Use it like this:
public static void Main(string[] args)
{
var list1 = new int?[] { 1, 2, 3, 4, 5 };
var list2 = new int?[] { 3, 4, 5, 6, 7 };
var list3 = new int?[] { 6, 9, 9 };
var lockstep = AlignSequences(new[] { list1, list2, list3 });
foreach (var step in lockstep)
Console.WriteLine(string.Join("\t", step.Select(i => i.HasValue ? i.Value.ToString() : "null").ToArray()));
}
It prints (for demo purposes I print the results sideways):
1 null null
2 null null
3 3 null
4 4 null
5 5 null
null 6 6
null 7 null
null null 9
null null 9
Note: You might like to change the interface to accept arbitrary number of lists, instead of a single sequence of sequences:
public static IEnumerable<IEnumerable<T>> AlignSequences<T>(params IEnumerable<T>[] sequences)
That way you could just call
var lockstep = AlignSequences(list1, list2, list3);
Here's another approach using List.BinarySearch.
sample data:
var list1 = new List<int>() { 1, 2, 3, 4 };
var list2 = new List<int>() { 2, 3, 5, 6, 7, 8 };
var list3 = new List<int>() { 3, 4, 5 };
var all = new List<List<int>>() { list1, list2, list3 };
calculate min/max and all nullable-lists:
int min = all.Min(l => l.Min());
int max = all.Max(l => l.Max());
// start from smallest number and end with highest, fill all between
int count = max - min + 1;
List<int?> l1Result = new List<int?>(count);
List<int?> l2Result = new List<int?>(count);
List<int?> l3Result = new List<int?>(count);
foreach (int val in Enumerable.Range(min, count))
{
if (list1.BinarySearch(val) >= 0)
l1Result.Add(val);
else
l1Result.Add(new Nullable<int>());
if (list2.BinarySearch(val) >= 0)
l2Result.Add(val);
else
l2Result.Add(new Nullable<int>());
if (list3.BinarySearch(val) >= 0)
l3Result.Add(val);
else
l3Result.Add(new Nullable<int>());
}
output:
Console.WriteLine(string.Join(",", l1Result.Select(i => !i.HasValue ? "NULL" : i.Value.ToString())));
Console.WriteLine(string.Join(",", l2Result.Select(i => !i.HasValue ? "NULL" : i.Value.ToString())));
Console.WriteLine(string.Join(",", l3Result.Select(i => !i.HasValue ? "NULL" : i.Value.ToString())));
1, 2, 3, 4, NULL, NULL, NULL, NULL
NULL, 2, 3, NULL, 5, 6, 7, 8
NULL, NULL, 3, 4, 5, NULL, NULL, NULL
DEMO

Categories