I have an array statsname as
apple
X
banana
Y
Kiwi
z
I need to put apple,banana and Kiwi in an array Fruits and X,Y and Z in an array called alphabets.
Any simple C# mechanism for it please ?
Use the IEnumerable<T>.Where overload which supplies the index.
var fruits = statsname.Where((s, i) => i % 2 == 0).ToArray();
var alphabets = statsname.Where((s, i) => i % 2 != 0).ToArray();
Stolen from How to get Alternate elements using Enumerable in C#
var fruits = myArray.Where((t, i) => i % 2 == 0).ToArray();
var alphabets = myArray.Where((t, i) => i % 2 == 1).ToArray();
If i have understood you question correctly what you want is very simple:
You want put fruits in array of fruits and same for alphabets and they are appearing alternatively in array statsname so:
for(int i=0,j=0;i<statsname.length;i+2,j++)
fruits[j]=statsname[i];
for(int i=1,j=0;i<statsname.length;i+2,j++)
alphabets[j]=statsname[i];
Single LINQ:
List<string> list = new List<string>() { "apple", "X", "banana", "Y", "Kiwi", "z" };
var result = list.Select((l, i) => new { l, i })
.GroupBy(p => p.i % 2)
.Select(x => x.Select(v => v.l).ToList())
.ToList();
Then you have a list of lists:
list<string> fruits = new List<string>();
list<string> alphabet = new List<string>();
for (int i = 0; i < array.Length; i++)
{
if (i % 2 == 0)
fruits.Add(array[i]);
else
alphabet.Add(array[i]);
}
Then you can just do .ToArray on the lists
string[] rawarray = new string [] {"Apple","X" .....};
string[] Fruites = new string[rawarray.Length/2+1];
string[] Alphabets = new string[rawarray.Length/2];
For(int i=0; i<rawarray.Length;i++)
{
if(i%2==0)
{
Fruits[i/2]=rawarray[i];
}
else
{
Alphabets[i/2]=rawarray[i];
}
}
using only Arrays:
var array = new string[] { "apple", "X", "banana", "Y", "Kiwi", "z" };
var fruit = new string[array.Length];
var alphabet = new string[array.Length];
for(var i = 0,j = 0; i < array.Length / 2; i++, j += 2)
{
fruit[i] = array[j];
alphabet[i] = array[j + 1];
}
You could make an iterator which just skips every other element. The idea is to have a "view" of a collection, special enumerable which will return only some of the elements:
static IEnumerable<T> everyOther<T>( IEnumerable<T> collection )
{
using( var e = collection.GetEnumerator() ) {
while( e.MoveNext() ) {
yield return e.Current;
e.MoveNext(); //skip one
}
}
}
You can use System.Linq.Skip to skip the first element.
string[] words = "apple X banana Y Kiwi z".Split();
var fruits = everyOther( words );
var alphabets = everyOther( words.Skip(1) );
Just use them as a new collection or call .ToArray() or .ToList() on them:
foreach( string f in fruits )
Console.WriteLine( f );
string[] anArray = fruits.ToArray(); //using System.Linq
Now you have what you need.
Iterators are methods which yield return, see Iterators (C# Programming Guide). This is very strong feature of the language. You can:
skip elements
decorate elements
change ordering
concatenate sequences (see System.Linq.Concat)
...
Here is some working code, hopefully this will be helpfull to you:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ReadFile
{
class Program
{
static void ReadFile(string filePath, List<string> custumerNames, List<int> phoneNumbers)
{
string line = string.Empty;
var fileStream = new StreamReader(filePath);
bool isPhoneNumber = true;
while ((line = fileStream.ReadLine()) != null)
{
if (isPhoneNumber)
{
phoneNumbers.Add(Convert.ToInt32(line));
isPhoneNumber = false;
}
else
{
custumerNames.Add(line);
isPhoneNumber = true;
}
}
fileStream.Close();
}
static void Main(string[] args)
{
Console.WriteLine("Started reading the file...");
List<string> custumersNamesList = new List<string>();
List<int> custumersPhonesNumbers = new List<int>();
ReadFile("SampleFile.txt", custumersNamesList, custumersPhonesNumbers);
//Assuming both the list's has same lenght.
for (int i = 0; i < custumersNamesList.Count(); i++)
{
Console.WriteLine(string.Format("Custumer Name: {0} , Custumer Phone Number: {1}",
custumersNamesList[i], Convert.ToString(custumersPhonesNumbers[i])));
}
Console.ReadLine();
}
}
}
Related
When i have a list
IList<int> list = new List<int>();
list.Add(100);
list.Add(200);
list.Add(300);
list.Add(400);
list.Add(500);
What is the way to extract a pairs
Example : List elements {100,200,300,400,500}
Expected Pair : { {100,200} ,{200,300} ,{300,400} ,{400,500} }
The most elegant way with LINQ: list.Zip(list.Skip(1), Tuple.Create)
A real-life example: This extension method takes a collection of points (Vector2) and produces a collection of lines (PathSegment) needed to 'join the dots'.
static IEnumerable<PathSegment> JoinTheDots(this IEnumerable<Vector2> dots)
{
var segments = dots.Zip(dots.Skip(1), (a,b) => new PathSegment(a, b));
return segments;
}
This will give you an array of anonymous "pair" objects with A and B properties corresponding to the pair elements.
var pairs = list.Where( (e,i) => i < list.Count - 1 )
.Select( (e,i) => new { A = e, B = list[i+1] } );
You can use a for loop:
var pairs = new List<int[]>();
for(int i = 0; i < list.Length - 1; i++)
pairs.Add(new [] {list[i], list[i + 1]);
You can also use LINQ, but it's uglier:
var pairs = list.Take(list.Count - 1).Select((n, i) => new [] { n, list[i + 1] });
EDIT: You can even do it on a raw IEnumerable, but it's much uglier:
var count = list.Count();
var pairs = list
.SelectMany((n, i) => new [] { new { Index = i - 1, Value = n }, new { Index = i, Value = n } })
.Where(ivp => ivp.Index >= 0 && ivp.Index < count - 1) //We only want one copy of the first and last value
.GroupBy(ivp => ivp.Index, (i, ivps) => ivps.Select(ivp => ivp.Value));
More general would be:
public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> values, int count, Func<TSource[], TResult> pairCreator)
{
if (count < 1) throw new ArgumentOutOfRangeException("count");
if (values == null) throw new ArgumentNullException("values");
if (pairCreator == null) throw new ArgumentNullException("pairCreator");
int c = 0;
var data = new TSource[count];
foreach (var item in values)
{
if (c < count)
data[c++] = item;
if (c == count)
{
yield return pairCreator(data);
c = 0;
}
}
}
Following solution uses zip method. Zip originalList and originalList.Skip(1) so that one gets desired result.
var adjacents =
originalList.Zip(originalList.Skip(1),
(a,b) => new {N1 = a, N2 = b});
Using .Windowed() from MoreLINQ:
var source = new[] {100,200,300,400,500};
var result = source.Windowed(2).Select(x => Tuple.Create(x.First(),x.Last()));
Off the top of my head and completely untested:
public static T Pairwise<T>(this IEnumerable<T> list)
{
T last;
bool firstTime = true;
foreach(var item in list)
{
if(!firstTime)
return(Tuple.New(last, item));
else
firstTime = false;
last = item;
}
}
I want to find two longest words from array ,made from smaller words. my code are given below.
current out put is:
catxdogcatsrat, ratcatdogcat, catsdogcats, dogcatsdog
required output is:
ratcatdogcat, catsdogcats
class program
{
public static void Main(String[] args)
{
List<string> list2 = new List<string>();
string[] stringrray = { "cat", "cats", "catsdogcats", "catxdogcatsrat", "dog", "dogcatsdog",
"hippopotamuses", "rat", "ratcatdogcat" };
list2.Add(stringrray[0]);
list2.Add(stringrray[1]);
list2.Add(stringrray[2]);
list2.Add(stringrray[3]);
list2.Add(stringrray[4]);
list2.Add(stringrray[5]);
list2.Add(stringrray[6]);
list2.Add(stringrray[7]);
list2.Add(stringrray[8]);
List<string> list = new List<string>();
var mod = list2.OrderByDescending(x => x.Length).ToList();
int j = 1;
for (int k = 0; k < mod.Count; k++)
{
for (int i = 0; i < mod.Count-j; i++)
{
if (mod[i].Contains(mod[mod.Count - j]))
{
j++;
list.Add(mod[i]);
}
}
}
var mod1 = list.OrderByDescending(x => x.Length);
foreach (var i in mod1)
{
Console.WriteLine(i);
}
Console.ReadLine();
}
}
I think you are looking for something like this
string[] stringrray = { "cat", "cats", "catsdogcats", "catxdogcatsrat", "dog", "dogcatsdog", "hippopotamuses", "rat", "ratcatdogcat" };
List<string> list2 = new List<string>(stringrray);
List<string> Finallist = new List<string>();
char[] smallstrchar = String.Join("", list2.Where(x => x.Length <= 4)).ToCharArray();
char[] bigstrchar = String.Join("", list2.Where(x => x.Length > 4)).ToCharArray();
char[] modchar = bigstrchar.Except(smallstrchar).ToArray();
foreach(string bigstr in list2)
{
if(!(bigstr.IndexOfAny(modchar) != -1))
{
Finallist.Add(bigstr);
}
}
Finallist = Finallist.OrderByDescending(x => x.Length).Take(2).ToList();
foreach(string finalstr in Finallist)
{
Console.WriteLine(finalstr);
}
So first is the stringrray which contains all the strings which are supposed to be taken care and find the longest one out of it. With your code it also takes the string which contains x in them but all other chars are matched. So I have made a list of strings in list2 which contains all the values. Then splitted the list2 in 2 parts that is smallstrchar array contains all the chars of the smaller strings less than length of 4 and Bigstrchar contains all chars of strings which are bigger than length of 5. Now Except takes out all the chars which does not exsist in the smallstrchar and present in Bigstrchar. Now we have the list of chars which need to be excluded from the sort.
Finally IndexOfAny to find in that string contains that char or not. If not then add to Finallist. Later we can take 2 from the list.
Hope this helps
You could simplify adding the array to list2 with
list2.AddRange(stringrray)
You may use this code...
static void Main(string[] args)
{
List<string> words = new List<string>() { "cat", "cats", "catsdogcats", "catxdogcatsrat", "dog", "dogcatsdog", "hippopotamuses", "rat", "ratcatdogcat" };
List<string> result = new List<string>();
// solution 1
foreach (string word in words)
{
if (IsCombinationOf(word, words))
{
result.Add(word);
}
}
// solution 2
result = words.Where(x => IsCombinationOf(x, words)).ToList();
}
public static bool IsCombinationOf(string word, List<string> parts)
{
// removing the actual word just to be secure.
parts = parts.Where(x => x != word).OrderByDescending(x => x.Length).ToList();
// erase each part in word. Only those which are not in the list will remain.
foreach (string part in parts)
{
word = Regex.Replace(word, part, "");
}
// if there are any caracters left, it hasn't been a combination
return word.Length == 0;
}
but...
This code has a little bug. The OrderbyDescending clause ensures that cats will be removed before cat. Otherwise the s would remain and the code wouldn't work as expected. But if we use some fictional values this code will not work properly. For example:
List<string> words = new List<string>() { "abz", "e", "zefg", "f", "g", "abzefg" };
Let's have a look at abzef. The algorithm will remove zefg first, but then it's not possible to go any futher. Indeed, the word is a combination of abz, e, f and g .
I have my code like,
string firstLineOfRecord = "front images,Currency Code,Date,BackImages,Domination";
string[] fieldArrayRecord = firstLineOfRecord.Split(',');
string fields = "FrontImages,BackImages,Domination,CurrencyCode,SerialNumber";
string[] fieldArrayList = fields.Split(',');
List<int> mappedList = new List<int>();
for (int i = 0; i< fieldArrayList.Count(); i++)
{
for (int j = 0; j < fieldArrayRecord.Count(); j++)
{
if (fieldArrayList[i] == fieldArrayRecord[j])
{
mappedList.Add(j);
}
}
}
How can i map, the "front Images" with "FrontImages".
As iam the beginner i dont know how to solve this.Kindly tell me how to achieve this.
For such a fuzzy match, you first need to identify the valid identifiers to ignore (in this case a space).
You could do something like this: You strip out all those identifiers. Then compare case and culture insensitive.
string normalizedHeaderString = "FrontImages";
string normalizedInputString = "front images";
foreach (string c in new[] { " " }) /* the strings to strip out */
{
normalizedHeaderString = normalizedHeaderString.Replace(c, null);
normalizedInputString = normalizedInputString.Replace(c, null);
}
if (string.Equals( normalizedHeaderString
, normalizedInputString
, StringComparison.OrdinalIgnoreCase
)
)
{ /* do your logic, like saving the index, etc */ }
This is a little hacky, but you get the idea. You'd better use a custom implementation of a StringComparer that just ignores the characters to strip out.
As I understand from your question, your problems are spaces and case sensitivity
so you can use
fieldArrayList[i].Replace(" ","").ToLower() ==
fieldArrayRecord[j].Replace(" ","").ToLower()
class Program
{
static void Main(string[] args)
{
string firstLineOfRecord = "front images,Currency Code,Date,BackImages,Domination";
string[] fieldArrayRecord = firstLineOfRecord.Split(',');
string fields = "FrontImages,BackImages,Domination,CurrencyCode,SerialNumber";
string[] fieldArrayList = fields.Split(',');
List<int> mappedList = new List<int>();
for (int i = 0; i < fieldArrayRecord.Length; i++)
{
if (fieldArrayList.Any(s => string.Equals( fieldArrayRecord[i].Replace(" ", string.Empty), s, StringComparison.OrdinalIgnoreCase)))
{
mappedList.Add(i);
}
}
foreach (int index in mappedList)
{
Console.WriteLine(index);
}
}
}
Output:
0
1
3
4
Or using a dictionary:
class Program
{
static void Main(string[] args)
{
string firstLineOfRecord = "front images,Currency Code,Date,BackImages,Domination";
string fields = "FrontImages,BackImages,Domination,CurrencyCode,SerialNumber";
var dataFields = firstLineOfRecord.Split(',').Select((x, index) => new { FieldName = x.Replace(" ", string.Empty), Index = index });
var tableFields = fields.Split(',').Select((x, index) => new { FieldName = x, Index = index });
Dictionary<int, int> mapping = (from dataField in dataFields
let tableField = tableFields.SingleOrDefault(x => string.Equals(dataField.FieldName, x.FieldName, StringComparison.OrdinalIgnoreCase))
where tableField != null
select new { DF = dataField.Index, TF = tableField.Index })
.ToDictionary(c => c.DF, c => c.TF);
// Test:
string[] dataFieldsArray = firstLineOfRecord.Split(',');
string[] tableFieldsArray = fields.Split(',');
foreach (KeyValuePair<int,int> pair in mapping)
{
Console.WriteLine(
"TableField '{0}' Index {1} has to be mapped to DataField '{2}' Index {3}",
tableFieldsArray[pair.Value], pair.Value, dataFieldsArray[pair.Key],pair.Key);
}
}
}
Output:
TableField 'FrontImages' Index 0 has to be mapped to DataField 'front images' Index 0
TableField 'CurrencyCode' Index 3 has to be mapped to DataField 'Currency Code' Index 1
TableField 'BackImages' Index 1 has to be mapped to DataField 'BackImages' Index 3
TableField 'Domination' Index 2 has to be mapped to DataField 'Domination' Index 4
Here's a way to do it with a LINQ query:
string firstLineOfRecord = "front images,Currency Code,Date,BackImages,Domination";
string[] fieldArrayRecord = firstLineOfRecord.Split(',')
.Select(x => x.Replace(" ", string.Empty))
.ToArray();
// Test it, prints True.
fieldArrayRecord.Contains("FrontImages", StringComparer.OrdinalIgnoreCase)
Note this will replace any white space between those letters and will alter the given fieldArrayRecord.
I am using the below code to read data from a text file row by row. I would like to assign each row into an array. I must be able to find the number or rows/arrays and the number of elements on each one of them.
I would also like to do some manipulations on some or all rows and return their values.
I get the number of rows, but is there a way to to loop something like:
*for ( i=1 to number of rows)
do
mean[i]<-row[i]
done
return mean*
var data = System.IO.File.ReadAllText("Data.txt");
var arrays = new List<float[]>();
var lines = data.Split(new[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines)
{
var lineArray = new List<float>();
foreach (var s in line.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries))
{
lineArray.Add(Convert.ToSingle(s));
}
arrays.Add(lineArray.ToArray());
}
var numberOfRows = lines.Count();
var numberOfValues = arrays.Sum(s => s.Length);
var arrays = new List<float[]>();
//....your filling the arrays
var averages = arrays.Select(floats => floats.Average()).ToArray(); //float[]
var counts = arrays.Select(floats => floats.Count()).ToArray(); //int[]
Not sure I understood the question. Do you mean something like
foreach (string line in File.ReadAllLines("fileName.txt")
{
...
}
Is it ok for you to use Linq? You might need to add using System.Linq; at the top.
float floatTester = 0;
List<float[]> result = File.ReadLines(#"Data.txt")
.Where(l => !string.IsNullOrWhiteSpace(l))
.Select(l => new {Line = l, Fields = l.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) })
.Select(x => x.Fields
.Where(f => Single.TryParse(f, out floatTester))
.Select(f => floatTester).ToArray())
.ToList();
// now get your totals
int numberOfLinesWithData = result.Count;
int numberOfAllFloats = result.Sum(fa => fa.Length);
Explanation:
File.ReadLines reads the lines of a file (not all at once but straming)
Where returns only elements for which the given predicate is true(f.e. the line must contain more than empty text)
new { creates an anonymous type with the given properties(f.e. the fields separated by comma)
Then i try to parse each field to float
All that can be parsed will be added to an float[] with ToArray()
All together will be added to a List<float[]> with ToList()
Found an efficient way to do this. Thanks for your input everybody!
private void ReadFile()
{
var lines = File.ReadLines("Data.csv");
var numbers = new List<List<double>>();
var separators = new[] { ',', ' ' };
/*System.Threading.Tasks.*/
Parallel.ForEach(lines, line =>
{
var list = new List<double>();
foreach (var s in line.Split(separators, StringSplitOptions.RemoveEmptyEntries))
{
double i;
if (double.TryParse(s, out i))
{
list.Add(i);
}
}
lock (numbers)
{
numbers.Add(list);
}
});
var rowTotal = new double[numbers.Count];
var rowMean = new double[numbers.Count];
var totalInRow = new int[numbers.Count()];
for (var row = 0; row < numbers.Count; row++)
{
var values = numbers[row].ToArray();
rowTotal[row] = values.Sum();
rowMean[row] = rowTotal[row] / values.Length;
totalInRow[row] += values.Length;
}
I'm looking to combine the contents of two string arrays, into a new list that has the contents of both joined together.
string[] days = { "Mon", "Tue", "Wed" };
string[] months = { "Jan", "Feb", "Mar" };
// I want the output to be a list with the contents
// "Mon Jan", "Mon Feb", "Mon Mar", "Tue Jan", "Tue Feb" etc...
How can I do it ? For when it's only two arrays, the following works and is easy enough:
List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
{
var combinedWords = new List<string>();
foreach (var wordOne in wordsOne)
{
foreach (string wordTwo in wordsTwo)
{
combinedWords.Add(wordOne + " " + wordTwo);
}
}
return combinedWords;
}
But I'd like to be able to pass varying numbers of arrays in (i.e. to have a method with the signature below) and have it still work.
List<string> CombineWords(params string[][] arraysOfWords)
{
// what needs to go here ?
}
Or some other solution would be great. If it's possible to do this simply with Linq, even better!
What you want to do is actually a cartesian product of all the arrays of words, then join the words with spaces. Eric Lippert has a simple implementation of a Linq cartesian product here. You can use it to implement CombineWords:
List<string> CombineWords(params string[][] arraysOfWords)
{
return CartesianProduct(arraysOfWords)
.Select(x => string.Join(" ", x))
.ToList();
}
To cross join on any amount of arrays of strings:
// Define other methods and classes here
List<string> CombineWords(params string[][] arraysOfWords)
{
if (arraysOfWords.Length == 0)
return new List<string>();
IEnumerable<string> result = arraysOfWords[0];
foreach( string[] words in arraysOfWords.Skip(1) )
{
var tempWords = words;
result = from r in result
from w in tempWords
select string.Concat(r, " ", w);
}
return result.ToList();
}
Code below works for any number of arrays (and uses linq to some degree):
List<string> CombineWords(params string[][] wordsToCombine)
{
if (wordsToCombine.Length == 0)
return new List<string>();
IEnumerable<string> combinedWords = wordsToCombine[0].ToList();
for (int i = 1; i < wordsToCombine.Length; ++i)
{
var temp = i;
combinedWords = (from x in combinedWords from y in wordsToCombine[temp]
select x + " " + y);
}
return combinedWords.ToList();
}
public static List<string> CombineWords(params string[][] arraysOfWords)
{
var strings = new List<string>();
if (arraysOfWords.Length == 0)
{
return strings;
}
Action<string, int> combineWordsInternal = null;
combineWordsInternal = (baseString, index) =>
{
foreach (var str in arraysOfWords[index])
{
string str2 = baseString + " " + str;
if (index + 1 < arraysOfWords.Length)
{
combineWordsInternal(str2, index + 1);
}
else
{
strings.Add(str2);
}
}
};
combineWordsInternal(string.Empty, 0);
return strings;
}
Second try... I'm not able to do it in LINQ... A little too much complex to linquize correctly :-)
I'm using a local anonymous function (and showing that it's quite complex to recurse on anonymous functions, because you have to declare them separately)
This is a non-recursive solution which buffers strings as it progresses, to reduce the number of concatenations. Therefore it should also be usable for more arrays.
It also preserves your desired order - the items in the first array will always be at the beginning of the resulting string.
var s1 = new string[] { "A", "B", "C" };
var s2 = new string[] { "1", "2", "3", "4" };
var s3 = new string[] { "-", "!", "?" };
var res = Combine(s1, s2, s3);
And the function in question:
private List<string> Combine(params string[][] arrays)
{
if (arrays.Length == 1)
{
// The trivial case - exit.
return new List<string>(arrays[0]);
}
IEnumerable<string> last = arrays[arrays.Length - 1];
// Build from the last array, progress forward
for (int i = arrays.Length - 2; i >= 0; i--)
{
var buffer = new List<string>();
var current = arrays[i];
foreach (var head in current)
{
foreach (var tail in last)
{
// Concatenate with the desired space.
buffer.Add(head + " " + tail);
}
}
last = buffer;
}
return (List<string>)last;
}
Could you try this method ?
static List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
{
var combinedWords = new List<string>();
for(int x = 0; (x <= wordsOne.Length - 1); ++x)
{
for(int y = 0; (x <= wordsTwo.Length - 1); ++y)
{
combinedWords.Add(string.Format("{0} {1}", wordsOne[x], wordsTwo[y]));
}
}
return combinedWords;
}
Kris