Suppose I have two arrays as follows
int[] first = { 1, 2, 3, 4, 5, 6, 12, 13, 14 };
int[] second = { 12, 13, 14, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
I want the result as follows:
matching index from the first = 6,7,8
matching index from second = 0,1,2
Condition: I cannot sort the array to find the index and there can be any number of the array.
I am looking for some efficient solution and I will be glad for the help.
Thanks in advance.
Below is the code I did for the two arrays:
class Program
{
static void Main(string[] args)
{
int[] first = { 1, 2, 3, 4, 5, 6, 12, 13, 14 };
int[] second = { 12, 13, 14, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 };
IndexArray sameIndexArray = CompareArray(first, second);
Console.WriteLine("FOLLOWING ARE THE INDEX WITH SAME VALUE FOR FIRST ARRAY");
foreach (var index in sameIndexArray.FirstArray)
{
Console.WriteLine(index);
}
Console.WriteLine("FOLLOWING ARE THE INDEX WITH SAME VALUE FOR SECOND ARRAY");
foreach (var index in sameIndexArray.SecondArray)
{
Console.WriteLine(index);
}
Console.ReadKey();
}
private static IndexArray CompareArray(int[] firstArray, int[] secondArray)
{
IndexArray arrayIndex = new IndexArray();
arrayIndex.FirstArray = new List<int>();
arrayIndex.SecondArray = new List<int>();
for (int i = 0; i < firstArray.Length; i++)
{
for (int j = 0; j < secondArray.Length; j++)
{
if (firstArray[i] == secondArray[j])
{
arrayIndex.FirstArray.Add(i);
arrayIndex.SecondArray.Add(j);
}
}
}
return arrayIndex;
}
}
public class IndexArray
{
public List<int> FirstArray { get; set; }
public List<int> SecondArray { get; set; }
}
Your solution is O(N^2). An O(N) or O(N log N) solution should be possible:
Create a HashSet for each of the sets
iterate over the first set, filtering by hashset2.Contains and print the indexes
do the same vice versa
Something like this:
private static IndexArray CompareArray(int[] firstArray, int[] secondArray)
{
IndexArray arrayIndex = new IndexArray();
var hashset2 = new HashSet<int>(secondArray);
for (int i = 0; i < firstArray.Length; i++)
{
if (hashset2.Contains(firstArray[i]))
arrayIndex.FirstArray.Add(i);
}
var hashset1 = new HashSet<int>(firstArray);
for (int i = 0; i < secondArray.Length; i++)
{
if (hashset1.Contains(secondArray[i]))
arrayIndex.SecondArray.Add(i);
}
return arrayIndex;
}
If this is working code it might be a better fit on code review.
I would drop the
arrayIndex.FirstArray = new List<int>();
arrayIndex.SecondArray = new List<int>();
Add
public List<int> FirstArray { get; } = new List<int>();
public List<int> SecondArray { get; } = new List<int>();
Arraylookup is fast but I would add
int first = firstArray[i];
And then use that.
WritelLine will write a line.
Related
one a integer list and one a string list. The integer list's length will always be a multiple of 8. I would like to put the first 8 integers from my integer list into the first element of a string list, then loop and put the next 8 into the second element of the string list and so on. I have made an attempt, I currently have an error on the Add method as string doesn't have an add extension? Also I'm not sure if the way I have done it using loops is correct, any advice would be helpful.
List1 is my integer list
List2 is my string list
string x = "";
for (int i = 0; i < List1.Count/8; i++) {
for(int i2 = 0; i2 < i2+8; i2+=8)
{
x = Convert.ToString(List1[i2]);
List2[i].Add(h);
}
}
You can do that by using something like that
var list1 = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
var list2 = new List<string>();
for (int i = 0; i < list1.Count / 8; i++)
{
list2.Add(string.Concat(list1.Skip(i * 8).Take(8)));
}
// list2[0] = "12345678"
// list2[1] = "910111213141516"
A slightly more complicated approach, which only iterates once over list1 (would work with IEnumerable would be sth. like this:
var list1 = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }.AsEnumerable();
var list2 = new List<string>();
var i = 0;
var nextValue = new StringBuilder();
foreach (var integer in list1)
{
nextValue.Append(integer);
i++;
if (i != 0 && i % 8 == 0)
{
list2.Add(nextValue.ToString());
nextValue.Clear();
}
}
// could add remaining items if count of list1 is not a multiple of 8
// if (nextValue.Length > 0)
// {
// list2.Add(nextValue.ToString());
// }
For the fun of it, you can implement your own general purpose Batch extension method. Good practice to understand extension methods, enumerators, iterators, generics and c#'s local functions:
static IEnumerable<IEnumerable<T>> Batch<T>(
this IEnumerable<T> source,
int batchCount,
bool throwOnPartialBatch = false)
{
IEnumerable<T> nextBatch(IEnumerator<T> enumerator)
{
var counter = 0;
do
{
yield return enumerator.Current;
counter += 1;
} while (counter < batchCount && enumerator.MoveNext());
if (throwOnPartialBatch && counter != batchCount) //numers.Count % batchCount is not zero.
throw new InvalidOperationException("Invalid batch size.");
}
if (source == null)
throw new ArgumentNullException(nameof(source));
if (batchCount < 1)
throw new ArgumentOutOfRangeException(nameof(batchCount));
using (var e = source.GetEnumerator())
{
while (e.MoveNext())
{
yield return nextBatch(e);
}
}
}
Using it is rather trivial:
var ii = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
var ss = ii.Batch(4, true)
.Select(b => string.Join(", ", b))
And sure enough, the output is:
1, 2, 3, 4
5, 6, 7, 8
9, 10, 11, 12
while (listOfintergers.Count() > 0)
{
var first8elements = listOfintergers.ConvertAll(t=>t.ToString()).Take(8);
listOfStrings.Add(string.Concat(first8elements));
listOfintergers = listOfintergers.Skip(8).ToList();
}
I'd like to sort multiple lists (variable number of them) into single list, but keeping the specific order. For example:
List A: { 1,2,3,4,5 }
List B: { 6,7,8 }
List C: { 9,10,11,12 }
Result List: { 1,6,9,2,7,10,3,8,11,4,12,5 }
The only idea I got was to remove the first element from each list and put it into resulting set (and repeat until all lists are empty), but maybe there is a better way that doesn't require to create copy of each list and doesn't affect the original lists as well?
I suggest using IEnumerator<T> to enumerate lists while they have items:
private static IEnumerable<T> Merge<T>(params IEnumerable<T>[] sources) {
List<IEnumerator<T>> enums = sources
.Select(source => source.GetEnumerator())
.ToList();
try {
while (enums.Any()) {
for (int i = 0; i < enums.Count;)
if (enums[i].MoveNext()) {
yield return enums[i].Current;
i += 1;
}
else {
// exhausted, let's remove enumerator
enums[i].Dispose();
enums.RemoveAt(i);
}
}
}
finally {
foreach (var en in enums)
en.Dispose();
}
}
Test
List<int> A = new List<int>() { 1, 2, 3, 4, 5 };
List<int> B = new List<int>() { 6, 7, 8 };
List<int> C = new List<int>() { 9, 10, 11, 12 };
var result = Merge(A, B, C)
.ToList();
Console.Write(string.Join(", ", result));
The outcome is
1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5
For more flexible use
public static string MergeArrays(params IList<int>[] items)
{
var result = new List<int>();
for (var i = 0; i < items.Max(x => x.Count); i++)
result.AddRange(from rowList in items where rowList.Count > i select rowList[i]);
return string.Join(",", result);
}
.
var a = new List<int>() { 1, 2, 3, 4, 5 };
var b = new List<int>() { 6, 7, 8 };
var c = new List<int>() { 9, 10, 11, 12, 0, 2, 1 };
var r = MergeArrays(a, b, c);
There is no sense in over complicating this in my opinion, why not use a simple for loop to accomplish what you need?
List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };
List<int> list2 = new List<int> { 6, 7, 8 };
List<int> list3 = new List<int> { 9, 10, 11, 12 };
List<int> resultList = new List<int>();
for (int i = 0; i < list1.Count || i < list2.Count || i < list3.Count; i++)
{
if (i < list1.Count) resultList.Add(list1[i]);
if (i < list2.Count) resultList.Add(list2[i]);
if (i < list3.Count) resultList.Add(list3[i]);
}
Result: 1,6,9,2,7,10,3,8,11,4,12,5
Here's a fairly simple way. It was fun to write up anyway.
No, it isn't the best, but it works and you could expand it to suit your needs of using a List<List<int>> very easily.
//Using arrays for simplicity, you get the idea.
int[] A = { 1, 2, 3, 4, 5 };
int[] B = { 6, 7, 8 };
int[] C = { 9, 10, 11, 12 };
List<int> ResultSet = new List<int>();
//Determine this somehow. I'm doing this for simplicity.
int longest = 5;
for (int i = 0; i < longest; i++)
{
if (i < A.Length)
ResultSet.Add(A[i]);
if (i < B.Length)
ResultSet.Add(B[i]);
if (i < C.Length)
ResultSet.Add(C[i]);
}
//ResultSet contains: { 1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5 }
As you can see, just pop this out into a method and loop through your lists of lists, properly determining the max length of all lists.
I'd go with:
static void Main(string[] args)
{
var a = new List<int>() { 1, 2, 3, 4, 5 };
var b = new List<int>() { 6, 7, 8 };
var c = new List<int>() { 9, 10, 11, 12 };
var abc = XYZ<int>(new[] { a, b, c }).ToList();
}
static IEnumerable<T> XYZ<T>(IEnumerable<IList<T>> lists)
{
if (lists == null)
throw new ArgumentNullException();
var finished = false;
for (int index = 0; !finished; index++)
{
finished = true;
foreach (var list in lists)
if (list.Count > index) // list != null (prior checking for count)
{
finished = false;
yield return list[index];
}
}
}
I had to use use IList to have indexer and Count. It doesn't creates anything (no enumerators, no lists, etc.), purely yield return.
For your problem I create static method, which can merge any collections as you want:
public static class CollectionsHandling
{
/// <summary>
/// Merge collections to one by index
/// </summary>
/// <typeparam name="T">Type of collection elements</typeparam>
/// <param name="collections">Merging Collections</param>
/// <returns>New collection {firsts items, second items...}</returns>
public static IEnumerable<T> Merge<T>(params IEnumerable<T>[] collections)
{
// Max length of sent collections
var maxLength = 0;
// Enumerators of all collections
var enumerators = new List<IEnumerator<T>>();
foreach (var item in collections)
{
maxLength = Math.Max(item.Count(), maxLength);
if(collections.Any())
enumerators.Add(item.GetEnumerator());
}
// Set enumerators to first item
enumerators.ForEach(e => e.MoveNext());
var result = new List<T>();
for (int i = 0; i < maxLength; i++)
{
// Add elements to result collection
enumerators.ForEach(e => result.Add(e.Current));
// Remobve enumerators, in which no longer have elements
enumerators = enumerators.Where(e => e.MoveNext()).ToList();
}
return result;
}
}
Example of using:
static void Main(string[] args)
{
var a = new List<int> { 1, 2, 3, 4, 5 };
var b = new List<int> { 6, 7, 8 };
var c = new List<int> { 9, 10, 11, 12 };
var result= CollectionsHandling.Merge(a, b, c);
}
When you understand how it works, it will be possible to reduce the method of smaller.
Shortest and probably slowest solution
int[] A = { 1, 2, 3, 4, 5 };
int[] B = { 6, 7, 8 };
int[] C = { 9, 10, 11, 12 };
var arrs = new[] { A, B, C };
var merged = Enumerable.Range(0, arrs.Max(a => a.Length))
.Select(x => arrs.Where(a=>a.Length>x).Select(a=>a[x]))
.SelectMany(x=>x)
.ToArray();
upd.
Another way to solve - I just refactored #Sinatr answer.
static IEnumerable<T> XYZ<T>(IEnumerable<IList<T>> lists)
{
if (lists == null)
throw new ArgumentNullException();
var index = 0;
while (lists.Any(l => l.Count > index))
{
foreach (var list in lists)
if (list.Count > index)
yield return list[index];
index++;
}
}
I want to load scenes randomly without repetition using c#. Any help would do.
Thanks.
int[] array = new int[] { 1, 2, 3, 4, 6, 8, 9, 10, 11, 12 };
List<int> list = new List<int>();
void Start()
{
list.AddRange(array);
}
int GetUniqueRandom(bool RemoveFromTheList)
{
if (list.Count == 0)
{
if (RemoveFromTheList)
{
list.AddRange(array);
}
else
{
return -1; // never repeat
}
}
int rand = Random.Range(0, 10);
int value = list[rand];
list.RemoveAt(rand); return value;
}
A nice clean way is to shuffle the array, then put all the elements in a stack. All you need to get a random element is to pop an item off the stack.
You will want to remove the list in the list of fields and replace with this;
Stack remainingScenes = new Stack();
Remove the content of the Start() method - you don't need it.
In your method to get a new number;
if (remainingScenes.Count == 0) {
int n = array.Length;
while (n > 1)
{
int k = rng.Next(n--);
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
foreach(var element in array) {
remainingScenes.Push(element);
}
}
return remainingScenes.Pop();
The shuffle method is from here.
Uhmmm, this looks very straightforward. Judging from your code, you only need a little modification to make it work..
List<int> list = new List<int>() { 1, 2, 3, 4, 6, 8, 9, 10, 11, 12 };
int GetUniqueRandom(bool RemoveFromTheList)
{
if (list.Count == 0)
{
return -1;//nothing in the list so return negative value
}
//generate random index from list
int randIndex = Random.Range(0, list.Count - 1);
int value = list[rand];
if(RemoveFromTheList)
{
list.RemoveAt(randIndex);
}
return value;
}
Try this:
int[] array = new int[] { 1, 2, 3, 4, 6, 8, 9, 10, 11, 12 };
Stack<int> stack = null;
Then initialize like this:
var rnd = new Random();
stack = new Stack<int>(array.OrderBy(x => rnd.Next()));
Now you just keep getting values from the stack until it is empty:
var value = stack.Pop();
I am programming in C# and I currently have the 2D array below:
int[,] results = {
{ 4, 7, 9, 3, 8, 6, 4},
{ 4, 8, 6, 4, 8, 5, 6},
{ 7, 3, 9, 2, 2, 1, 8}
};
I'd like to create a loop or function which outputs 3 separate arrays, copying the values from each row.
e.g. output:
row1 = {4, 7, 9, 3, 8, 6, 4}
row2 = {4, 8, 6, 4, 8, 5, 6}
etc
I have been able to copy the values of each row into a separate string which is then written in the console with this line of code:
for (int a = 1; a < (rows+1); a++)
{
for (int b = 1; b < (columns+1); b++)
{
scores = scores + " " + results[(a-1), (b-1)];
}
scores = "";
}
you need a convertion from a 2D array into a jagged array
int[,] array = { { 4, 7, 9, 3, 8, 6, 4},
{ 4, 8, 6, 4, 8, 5, 6},
{ 7, 3, 9, 2, 2, 1, 8}
};
int[][] jagged = new int[array.GetLength(0)][];
for (int i = 0; i < array.GetLength(0); i++)
{
int[] row = new int[array.GetLength(1)];
for (int j = 0; j < array.GetLength(1); j++)
{
row[j] = array[i, j];
}
jagged[i] = row;
}
int[] row1 = jagged[0];
int[] row2 = jagged[1];
int[] row3 = jagged[2];
difference between multidimensional array and jagged array:
//multidimensional array
int[,] multi = { { 7, 2, 6, 1 }, { 3, 5, 4, 8 } };
//array of arrays (jagged array)
int[][] jagged = new int[][] { new int[] { 7, 2, 6, 1 }, new int[] { 3, 5, 4, 8 } };
LINQ variant:
var m0 = new int[,] { { 1, 2 }, { 3, 4 } };
var rows = Enumerable.Range(0, m0.GetLength(0)).Select(i => Enumerable.Range(0, m0.GetLength(1)).Select(j => m0[i, j]));
foreach (var r in rows) Console.WriteLine(string.Join(" ", r));
Console.ReadLine();
a 'smarter' variant (flattern an array and take by N values):
var rows = m0.Cast<int>().Select((v, i) => new { i = i / m0.GetLength(1), v }).GroupBy(e => e.i).Select(g => g.Select(e => e.v));
Just a piece of cake using JsonSoft as
var json = JsonConvert.SerializeObject(results);
int[][] arr = JsonConvert.DeserializeObject<int[][]>(json);
int[] arr1 = arr[0];
int[] arr2 = arr[1];
int[] arr3 = arr[2];
Let's say I have a list of predefined numbers, and a list of predefined max limits.
When a user picks a limit, I need to randomly pick a certain amount of numbers from the first list, up until their totals match (As close to, but never over) the user selected total.
What I've tried so far:
void Main()
{
List<int> num = new List<int>(){ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,17, 18, 19, 20 };
int maxNum = 17;
List<int> curNum = new List<int>();
int curTotal = 0;
foreach(int sel in num.Where(x => x < maxNum)){
curTotal += sel;
if(curTotal <= maxNum){
curNum.Add(sel);
}
}
}
There needs to be x amount of numbers picked. In this case, 5 numbers picked, +- 20 numbers to be randomly picked from, and 1 max values.
So the end list should look like this:
1, 2, 3, 4, 7 (17)
1, 2, 3, 5, 6 (17)
1, 2, 3, 4, 6 (16) <- This will be fine if there isn't a solution to the max value.
Building upon #AlexiLevenkov's answer:
class Program
{
static void Main(string[] args)
{
int limit = 17;
int listSize = 5;
List<int> a = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
a.Shuffle();
List<int> genList = new List<int>();
int stoppedCount = 0;
for (int i = 0; i < a.Count(); i++)
{
if (i < listSize)
{
genList.Add(a[i]);
stoppedCount = i;
}
else
{
break;
}
}
while (genList.Sum() > limit)
{
genList.Remove(genList.Max());
stoppedCount++;
genList.Add(a[stoppedCount]);
}
}
}
static class ThisClass
{
public static void Shuffle<T>(this IList<T> list)
{
Random rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
I think shuffle + "take while sum < limit" may be what you are looking for.
Something like following:
var shuffledList = num.ToList();
shuffledList.Shuffle();
var sum = 0;
var count = 0;
while (shuffledList[count] + sum < max)
{
sum += shuffledList[count++];
}
return shuffledList.Take(count);