Edit: I have tried the Take/Skip method but I get the following error:
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<string>' to
'string[]'. An explicit conversion exists (are you missing a cast?)
I do not know what I am doing wrong because I copied Saeed's code.
I have a string array (containing anywhere from 20 to 300 items) and I want to split it into 2 separate arrays, from the middle of the first one.
I know how I can do this using a for loop but I would like to know if there was a faster/better way of doing it. I also need to be able to correctly split an array even if it has an odd number of items, eg:
string[] words = {"apple", "orange", "banana", "pear", "lemon"};
string[] firstarray, secondarray;
SplitArray(words, out firstarray, out secondarray); // Or some other function
// firstarray has the first 3 of the items from words, 'apple', 'orange' and 'banana'
// secondarray has the other 2, 'pear' and 'lemon'
You can use linq:
firstArray = array.Take(array.Length / 2).ToArray();
secondArray = array.Skip(array.Length / 2).ToArray();
Why this works, despite the parity of the original array size?
The firstArray takes array.Length / 2 elements, and the second one skips the first array.Length / 2 elements, it means there isn't any conflict between these two arrays. Of course if the number of elements is odd we cannot split the array into two equal size parts.
If you want to have more elements in the first half (in the odd case), do this:
firstArray = array.Take((array.Length + 1) / 2).ToArray();
secondArray = array.Skip((array.Length + 1) / 2).ToArray();
string[] words = {"apple", "orange", "banana", "pear", "lemon"};
int mid = words.Length/2;
string[] first = words.Take(mid).ToArray();
string[] second = words.Skip(mid).ToArray();
If you don't want to/can't use LINQ you can simply do:
string[] words = { "apple", "orange", "banana", "pear", "lemon" };
string[] firstarray, secondarray;
int mid = words.Length / 2;
firstarray = new string[mid];
secondarray = new string[words.Length - mid];
Array.Copy(words, 0, firstarray, 0, mid);
Array.Copy(words, mid, secondarray, 0, secondarray.Length);
A more generalized approach that will split it into as many parts as you specify:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
return list.Select((item, index) => new {index, item})
.GroupBy(x => (x.index + 1) / (list.Count()/parts) + 1)
.Select(x => x.Select(y => y.item));
}
*Edited Thanks skarmats
string[] words = { "apple", "orange", "banana", "pear", "lemon" };
var halfWay = words.Length/2;
var firstHalf = words.Take(halfWay);
var secondHalf = words.Skip(halfWay);
You can achive that quite easily using range notation:
var x = new[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
var pivot = x.Length / 2;
var p1 = x[..pivot];
var p2 = x[pivot..];
Just in case someone wants to use a function instead:
static void Main(string[] args)
{
string[] ar = { "apple", "orange", "banana", "pear", "lemon" };
int half = ar.Length / 2;
// Console.WriteLine(string.Join(',', Split(ar,0, half)));
Console.WriteLine(string.Join(',', Split(ar,half, ar.Length)));
Console.ReadKey();
}
public static IEnumerable<T> Split<T>(IEnumerable<T> items, int start, int end)
{
return items.Skip(start).Take(end);
}
Related
Say I've got an
Array1 [1,2,3]
and a List of arrays Array2 [3,2,4] Array3 [2,16,5]
I need to return only those elements of the List which contain exactly two ints from Array1. In this case, Array2 since integers 2 and 3 intersect;
Thanks
Try to combine Where() and Count():
var matches = new int[] { 1, 2, 3 };
var data = new List<int[]>
{
new int[] { 3, 2, 4 },
new int[] { 2, 16, 5 }
};
var result = data.Where(x => x.Count(matches.Contains) == 2);
since it's int[] you can use the .Intersect() directly. For example
from a in arrays where a.Intersect(Array1).Count() == 2 select a
//arrays contains Array2 and Array3
i want to generate random number from two list. i want to create a function where i pass how much random number from two list.
List<int> integers = new List<int>() { 54, 23, 76, 123, 93, 7, 3489 };
List<int> value2 = new List<int>() { 1, 3, 4, 6, 8, 17, 40 };
i want my result = List<int> result = {54,40,123,17,3,1,3489,76...etc}
When i run again the set of result will be change.
Presently i am using this function that return List
public static List<int> GenerateRandom(int count)
{
// generate count random values.
HashSet<int> candidates = new HashSet<int>();
while (candidates.Count < count)
{
// May strike a duplicate.
candidates.Add(random.Next(1,30));
}
// load them in to a list.
List<int> result = new List<int>();
result.AddRange(candidates);
// shuffle the results:
int i = result.Count;
while (i > 1)
{
i--;
int k = random.Next(i + 1);
int value = result[k];
result[k] = result[i];
result[i] = value;
}
return result;
}
i am calling the function
List<int> vals = GenerateRandom(20);
But i want that the random number from two List<> List<int> integers and List<int> value2 . so how can i do this .
You can do something like this:
var result =
integers.Concat(value2)
.OrderBy(x => random.Next())
.Take(count)
.ToList();
You could write a general-purpose function to give you a random ordering of any number of sequences, like so:
public static IReadOnlyCollection<T> InRandomOrder<T>(Random rng, params IEnumerable<T>[] lists)
{
return lists
.SelectMany(x => x)
.OrderBy(y => rng.Next())
.ToList();
}
You can then pass as many lists as you like and get the contents back in a fully randomised order:
var list1 = new[] {1, 2, 3, 4, 5};
var list2 = new[] {6, 7, 8};
var list3 = new[] {9, 0};
Random rng = new Random();
for (int i = 0; i < 10; ++i)
{
var randomisedFirst5 = InRandomOrder(rng, list1, list2, list3).Take(5);
Console.WriteLine(string.Join(", ", randomisedFirst5));
}
There's a less efficient approach you can use that avoids the need for an instance of Random, but you should only use this for short lists or where you really don't care about performance. It uses Guid.NewGuid() to generate random numbers:
public static IReadOnlyCollection<T> InRandomOrder<T>(params IEnumerable<T>[] lists)
{
return lists
.SelectMany(x => x)
.OrderBy(y => Guid.NewGuid())
.ToList();
}
Even the more efficient approach isn't the fastest. A faster way would be to use reservoir sampling to take the first N items that you want, and put them into an array which you shuffle using Knuth. That would make it a lot faster, at the expense of more complicated code - meaning you should only do it the fast way if it's really needed.
If what you want is to select a number that exists either in list A or B, randomly, you can do:
List<int> integers = new List<int>() { 54, 23, 76, 123, 93, 7, 3489 };
List<int> value2 = new List<int>() { 1, 3, 4, 6, 8, 17, 40 };
List<int> allInOne = new List<int>(integers.Concat(value2));
Random r = new Random(DateTime.Now.Millisecond);
/********************************
For demonstration purposes
********************************/
for(int i = 0; i < 5; i++)
{
var randomListIndex = r.Next(0, allInOne.Count - 1);
Console.WriteLine(allInOne[randomListIndex]);
}
Use KeyValuePair
static void Main(string[] args)
{
List<KeyValuePair<int, int>> results = GenerateRandom(100);
}
static List<int> integers = new List<int>() { 54, 23, 76, 123, 93, 7, 3489 };
static List<int> value2 = new List<int>() { 1, 3, 4, 6, 8, 17, 40 };
static Random random = new Random();
public static List<KeyValuePair<int,int>> GenerateRandom(int count)
{
List<KeyValuePair<int,int>> result = new List<KeyValuePair<int,int>>();
for(int i = 0; i < count; i++)
{
int firstValue = integers[random.Next(0, integers.Count - 1)];
int seconValue = value2[random.Next(0, value2.Count - 1)];
result.Add(new KeyValuePair<int,int>(firstValue,seconValue));
}
return result;
}
I actually made a library a while back that handles some of this stuff : Underscore.cs
It's a nuget package so easy to install, the code to shuffle or take a sample randomly of two lists is :
var ls1 = GenerateRandom(10);
var ls2 = GenerateRandom(20);
var mixer = ls1.Concat(ls2).ToList();
//if you want all of the items shuffled use shuffle
var result = _.List.Shuffle(mixer);
//or if you want a subset randomly sorted use sample
result = _.List.Sample(mixer);
The current problem is that the code works, but it gets exponentially slower as more combinations are passed in. (The calculation takes > 5 seconds after 15 combinations are passed in.) I need to be able to pass in up to 100 combinations and still get a result back that takes less than 2 seconds.
I'm betting that a Linq query could solve this?
What I want to achieve:
{1, 2, 3} + {1, 5, 26, 40} = 12 combinations:
[1,1]
[1,5]
[1,26]
[1,40]
[2,1]
[2,5]
[2,26]
[2,40]
[3,1]
[3,5]
[3,26]
[3,40]
However, this example above only includes 2 combination sets. I should be able to pass in any number of combination sets.
The closest thing that looks like it is similar to what I want as an end result, due to being fast and efficient, is a linq query that handles most or all of the logic within it. Example: Getting all possible combinations from a list of numbers
public IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Example of working code:
[Test]
public void StackOverflowExample_Simple()
{
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 1, 5, 26, 40 };
var myListsOfNumberCombinations = new List<List<int>>() { list1, list2 };
var results = GetAllPossibleCombinations(myListsOfNumberCombinations);
Assert.AreEqual(12, results.Count());
StringBuilder sb = new StringBuilder();
foreach (var result in results)
{
foreach (var number in result.OrderBy(x => x))
{
sb.Append(number + ",");
}
sb.Append("|");
}
string finalResult = sb.ToString().Replace(",|", "|");
Assert.AreEqual(finalResult, "1,1|1,5|1,26|1,40|1,2|2,5|2,26|2,40|1,3|3,5|3,26|3,40|");
}
[Test]
public void StackOverflowExample_TakesALongTime()
{
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 4, 5 };
var list3 = new List<int>() { 1, 6 };
var list4 = new List<int>() { 2, 5 };
var list5 = new List<int>() { 1, 3, 55, 56 };
var list6 = new List<int>() { 3, 4, 7, 8, 9 };
var myListsOfNumberCombinations = new List<List<int>>() { list1, list2, list3, list4, list5, list1, list1, list1, list3, list4, list4, list5, list6, list6, list2 };
DateTime startTime = DateTime.Now;
var results = GetAllPossibleCombinations(myListsOfNumberCombinations);
Assert.AreEqual(4147200, results.Count());
var duration = DateTime.Now.Subtract(startTime).TotalSeconds;
//duration = about 4 or 5 seconds
Assert.Less(duration, 10); //easy place to put a breakpoint
}
public IEnumerable<IEnumerable<int>> GetAllPossibleCombinations(List<List<int>> combinationSets)
{
List<List<int>> returnList = new List<List<int>>();
_RecursiveGetMoreCombinations(
ref returnList,
new List<int>(),
combinationSets,
0);
return returnList;
}
private void _RecursiveGetMoreCombinations(
ref List<List<int>> returnList,
List<int> appendedList,
List<List<int>> combinationSets,
int index)
{
var combinationSet = combinationSets[index];
foreach (var number in combinationSet)
{
List<int> newList = appendedList.AsEnumerable().ToList();
newList.Add(number);
if (combinationSets.Count() == index + 1)
{
returnList.Add(newList);
}
else
{
_RecursiveGetMoreCombinations(
ref returnList,
newList,
combinationSets,
index + 1);
}
}
}
Can you not just do permutations of the first and third sets (the OR sets) and then place '45' (the AND set), or whatever the static numbers are, in between those numbers?
You don't need to include 4 and 5 (in this example) in the permutation logic if they are always going to be present.
Last night I had dream that the following was impossible. But in the same dream, someone from SO told me otherwise. Hence I would like to know if it it possible to convert System.Array to List
Array ints = Array.CreateInstance(typeof(int), 5);
ints.SetValue(10, 0);
ints.SetValue(20, 1);
ints.SetValue(10, 2);
ints.SetValue(34, 3);
ints.SetValue(113, 4);
to
List<int> lst = ints.OfType<int>(); // not working
Save yourself some pain...
using System.Linq;
int[] ints = new [] { 10, 20, 10, 34, 113 };
List<int> lst = ints.OfType<int>().ToList(); // this isn't going to be fast.
Can also just...
List<int> lst = new List<int> { 10, 20, 10, 34, 113 };
or...
List<int> lst = new List<int>();
lst.Add(10);
lst.Add(20);
lst.Add(10);
lst.Add(34);
lst.Add(113);
or...
List<int> lst = new List<int>(new int[] { 10, 20, 10, 34, 113 });
or...
var lst = new List<int>();
lst.AddRange(new int[] { 10, 20, 10, 34, 113 });
There is also a constructor overload for List that will work... But I guess this would required a strong typed array.
//public List(IEnumerable<T> collection)
var intArray = new[] { 1, 2, 3, 4, 5 };
var list = new List<int>(intArray);
... for Array class
var intArray = Array.CreateInstance(typeof(int), 5);
for (int i = 0; i < 5; i++)
intArray.SetValue(i, i);
var list = new List<int>((int[])intArray);
Interestingly no one answers the question, OP isn't using a strongly typed int[] but an Array.
You have to cast the Array to what it actually is, an int[], then you can use ToList:
List<int> intList = ((int[])ints).ToList();
Note that Enumerable.ToList calls the list constructor that first checks if the argument can be casted to ICollection<T>(which an array implements), then it will use the more efficient ICollection<T>.CopyTo method instead of enumerating the sequence.
The simplest method is:
int[] ints = new [] { 10, 20, 10, 34, 113 };
List<int> lst = ints.ToList();
or
List<int> lst = new List<int>();
lst.AddRange(ints);
In the case you want to return an array of enums as a list you can do the following.
using System.Linq;
public List<DayOfWeek> DaysOfWeek
{
get
{
return Enum.GetValues(typeof(DayOfWeek))
.OfType<DayOfWeek>()
.ToList();
}
}
in vb.net just do this
mylist.addrange(intsArray)
or
Dim mylist As New List(Of Integer)(intsArray)
You can do like this basically:
int[] ints = new[] { 10, 20, 10, 34, 113 };
this is your array, and than you can call your new list like this:
var newList = new List<int>(ints);
You can do this for complex object too.
You can just give it try to your code:
Array ints = Array.CreateInstance(typeof(int), 5);
ints.SetValue(10, 0);
ints.SetValue(20, 1);
ints.SetValue(10, 2);
ints.SetValue(34, 3);
ints.SetValue(113, 4);
int[] anyVariable=(int[])ints;
Then you can just use the anyVariable as your code.
I know two methods:
List<int> myList1 = new List<int>(myArray);
Or,
List<int> myList2 = myArray.ToList();
I'm assuming you know about data types and will change the types as you please.
Just use the existing method.. .ToList();
List<int> listArray = array.ToList();
KISS(KEEP IT SIMPLE SIR)
I hope this is helpful.
enum TESTENUM
{
T1 = 0,
T2 = 1,
T3 = 2,
T4 = 3
}
get string value
string enumValueString = "T1";
List<string> stringValueList = typeof(TESTENUM).GetEnumValues().Cast<object>().Select(m =>
Convert.ToString(m)
).ToList();
if(!stringValueList.Exists(m => m == enumValueString))
{
throw new Exception("cannot find type");
}
TESTENUM testEnumValueConvertString;
Enum.TryParse<TESTENUM>(enumValueString, out testEnumValueConvertString);
get integer value
int enumValueInt = 1;
List<int> enumValueIntList = typeof(TESTENUM).GetEnumValues().Cast<object>().Select(m =>
Convert.ToInt32(m)
).ToList();
if(!enumValueIntList.Exists(m => m == enumValueInt))
{
throw new Exception("cannot find type");
}
TESTENUM testEnumValueConvertInt;
Enum.TryParse<TESTENUM>(enumValueString, out testEnumValueConvertInt);
Lets say I have this array,
int[] numbers = {1, 3, 4, 9, 2};
How can I delete an element by "name"? , lets say number 4?
Even ArrayList didn't help to delete?
string strNumbers = " 1, 3, 4, 9, 2";
ArrayList numbers = new ArrayList(strNumbers.Split(new char[] { ',' }));
numbers.RemoveAt(numbers.IndexOf(4));
foreach (var n in numbers)
{
Response.Write(n);
}
If you want to remove all instances of 4 without needing to know the index:
LINQ: (.NET Framework 3.5)
int[] numbers = { 1, 3, 4, 9, 2 };
int numToRemove = 4;
numbers = numbers.Where(val => val != numToRemove).ToArray();
Non-LINQ: (.NET Framework 2.0)
static bool isNotFour(int n)
{
return n != 4;
}
int[] numbers = { 1, 3, 4, 9, 2 };
numbers = Array.FindAll(numbers, isNotFour).ToArray();
If you want to remove just the first instance:
LINQ: (.NET Framework 3.5)
int[] numbers = { 1, 3, 4, 9, 2, 4 };
int numToRemove = 4;
int numIndex = Array.IndexOf(numbers, numToRemove);
numbers = numbers.Where((val, idx) => idx != numIndex).ToArray();
Non-LINQ: (.NET Framework 2.0)
int[] numbers = { 1, 3, 4, 9, 2, 4 };
int numToRemove = 4;
int numIdx = Array.IndexOf(numbers, numToRemove);
List<int> tmp = new List<int>(numbers);
tmp.RemoveAt(numIdx);
numbers = tmp.ToArray();
Edit: Just in case you hadn't already figured it out, as Malfist pointed out, you need to be targetting the .NET Framework 3.5 in order for the LINQ code examples to work. If you're targetting 2.0 you need to reference the Non-LINQ examples.
int[] numbers = { 1, 3, 4, 9, 2 };
numbers = numbers.Except(new int[]{4}).ToArray();
You can also convert your array to a list and call remove on the list. You can then convert back to your array.
int[] numbers = {1, 3, 4, 9, 2};
var numbersList = numbers.ToList();
numbersList.Remove(4);
The code that is written in the question has a bug in it
Your arraylist contains strings of " 1" " 3" " 4" " 9" and " 2" (note the spaces)
So IndexOf(4) will find nothing because 4 is an int, and even "tostring" would convert it to of "4" and not " 4", and nothing will get removed.
An arraylist is the correct way to go to do what you want.
I posted my solution here.
This is a way to delete an array element without copying to another array - just in frame of the same array instance:
public static void RemoveAt<T>(ref T[] arr, int index)
{
for (int a = index; a < arr.Length - 1; a++)
{
// moving elements downwards, to fill the gap at [index]
arr[a] = arr[a + 1];
}
// finally, let's decrement Array's size by one
Array.Resize(ref arr, arr.Length - 1);
}
Removing from an array itself is not simple, as you then have to deal with resizing. This is one of the great advantages of using something like a List<int> instead. It provides Remove/RemoveAt in 2.0, and lots of LINQ extensions for 3.0.
If you can, refactor to use a List<> or similar.
Balabaster's answer is correct if you want to remove all instances of the element. If you want to remove only the first one, you would do something like this:
int[] numbers = { 1, 3, 4, 9, 2, 4 };
int numToRemove = 4;
int firstFoundIndex = Array.IndexOf(numbers, numToRemove);
if (numbers >= 0)
{
numbers = numbers.Take(firstFoundIndex).Concat(numbers.Skip(firstFoundIndex + 1)).ToArray();
}
As a generic extension, 2.0-compatible:
using System.Collections.Generic;
public static class Extensions {
//=========================================================================
// Removes all instances of [itemToRemove] from array [original]
// Returns the new array, without modifying [original] directly
// .Net2.0-compatible
public static T[] RemoveFromArray<T> (this T[] original, T itemToRemove) {
int numIdx = System.Array.IndexOf(original, itemToRemove);
if (numIdx == -1) return original;
List<T> tmp = new List<T>(original);
tmp.RemoveAt(numIdx);
return tmp.ToArray();
}
}
Usage:
int[] numbers = {1, 3, 4, 9, 2};
numbers = numbers.RemoveFromArray(4);
You can do in this way:
int[] numbers= {1,3,4,9,2};
List<int> lst_numbers = new List<int>(numbers);
int required_number = 4;
int i = 0;
foreach (int number in lst_numbers)
{
if(number == required_number)
{
break;
}
i++;
}
lst_numbers.RemoveAt(i);
numbers = lst_numbers.ToArray();
' To remove items from string based on Dictionary key values.
' VB.net code
Dim stringArr As String() = "file1,file2,file3,file4,file5,file6".Split(","c)
Dim test As Dictionary(Of String, String) = New Dictionary(Of String, String)
test.Add("file3", "description")
test.Add("file5", "description")
stringArr = stringArr.Except(test.Keys).ToArray()
public int[] DeletePart(int position, params int[] numbers)
{
int[] result = new int[numbers.Length - 1];
int z=0;
for (int i = 0; i < numbers.Length; i++)
{
if (position - 1 != i)
{
result[z] = numbers[i];
z++;
}
}
return result;
}
We can delete array elements by using for loops and continue statements:
string[] cars = {"volvo", "benz", "ford", "bmw"};
for (int i = 0; i < cars.Length; i++)
{
if (cars[i] == "benz")
{
continue;
}
Console.WriteLine(cars[i]);
}