I want to check if an empty string exists in an array after a specified index.
Suppose I have this array:
string[] values = {"1", "2", "2", "4", "", "", ""};
I want to check if an empty value exists from index 3 (where the value is 4). I want to do this without splitting it inter two different arrays of strings.
More specifically my example using an array named files
string[] files;
I want to check from array index 8 to array index 28 if there are any empty values.
You can do it with LINQ:
files.Skip(index).Any(s => s == string.Empty);
You can just use a for loop. Try this:
for(int i = specifiedIndex; i < array.Length; i++)
{
if(array[i].Equals(""))
return true;
}
return false;
This will return true if any of the values at or after the index are empty. If it reaches the end without finding one, it returns false.
You can adjust this to fit your needs. You don't necessarily have to loop the the end of the array, you can set the end condition to a specified index too, say if you wanted to check for an empty string between indexes 5 and 10 but don't care if there are any before or after that.
Use LINQ:-
string[] Values = { "1", "2", "2", "4", "", "", "" };
int specifiedIndex = 3;
var query1 = Values.Skip(specifiedIndex).Select((v, index) => new { v, index }).Where(x => x.v == String.Empty).Select(z => z.index + specifiedIndex);
foreach (var val in query1)
{
Console.WriteLine(val);
}
Related
I tried to solve a problem few days ago and almost solved with the help of SO. Unfortunately stuck into a situation that am unable to sort out. Here's the scenario:
Input:
[7, "aaa", "a", "cccccccccc", 5]
Output:
["a", "aaa", 5, 7, "cccccccccc"]
So you can see depending upon the number of letters in the element, the array should be sorted. In case of number, that should be sorted as well. At one point, the below code worked:
//Dynamic list where we can have string and integers
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(5);
aLst.Add("cccccc");
int val;
//What I did here, converted all items into string
//Checks if the list contains string
var letters = aLst.Where(i => !int.TryParse(i.ToString(), out val)).OrderBy(i => i.Length).ToList();
//Checks if the list contains number
var numbers = aLst.Where(i => int.TryParse(i.ToString(), out val)).OrderBy(i => int.Parse(i.ToString())).ToList();
//Finally from the number result set, taking the numbers to get their indexes and set them into the list accordingly
foreach (var number in numbers)
{
//Checks number index
var index = int.Parse(number.ToString());
if (letters.Count() >= index)
{
letters.Insert(index, number); //Assign index to numbers
}
else
{
letters.Insert(number);
}
}
foreach(var value in letters)
{
Console.WriteLine(value);
}
The above code gets me the expected result. But when the input is something as follows, it returns different result set that I can't able to set accordingly:
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(10);
aLst.Add(5);
aLst.Add("cccccc");
aLst.Add("cccccccccccc");
The result I get:
["a", 2, "aa", "aaa", 5, "cccc", 7, "cccccc", "cccccccccccc", 10]
Expected output:
["a", 2, "aa", "aaa", "cccc", 5, "cccccc", 7, 10, "cccccccccccc"]
Anything that I am doing wrong here or missed something? Any idea would be appreciated.
Code snippet: Sort Array Elements
The key here is to check the type of the object. If is a string, use the string's length for the order, otherwise assume it is an int and use the value itself for the order.
This will throw an exception if there are something else in the object list, for example an instance of some random class.
var list = new List<object> { 7, "aaa", "a", "cccccccccc", 5 };
// this assumes the elements in the array above (which can be anything) are only strings or integer
var ordered = list.OrderBy(x => x is string str ? str.Length : (int)x).ToList();
// print array to see results
Console.WriteLine(string.Join(",", ordered));
I hope i understood your sorting intension correctly. You could use a custom comparer to isolate the comparison logic which could check if it is a string or a number. For example,
public class Comparer : IComparer<object>
{
public int Compare(object a, object b)
{
var valA = GetValue(a);
var valB = GetValue(b);
return valA.CompareTo(valB);
}
private int GetValue(object ch)
{
if(Int32.TryParse(ch.ToString(),out var val))
return val;
else
return ch.ToString().Length;
}
}
You could now use the Custom comparer with Linq easily.
var output = list.OrderBy(x=>x, new Comparer())
Note that this assumes you are dealing with strings and numbers only. If you need to include other types, you could include the required logic within the Custom Comparer
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(5);
aLst.Add("cccccc");
for (int i = 0; i < aLst.Count; i++)
{
if (aLst[i] is int val)
{
aLst.RemoveAt(i);
aLst.Insert(0, val);
}
}
//var ty = aLst.Select(x => x.ToString());
var ordered = aLst.OrderBy(x => x is string str ? str.Length : (int)x).ToList();
Console.WriteLine(string.Join(",", ordered)); //a,2,aa,aaa,cccc,5,cccccc,7
i am getting string array on runtime like this
string[] array1 = {"5", "4", "2"};
values in array is added on runtime on the basis of checkbox selection from
screen (Note: i have 7 check boxes on screen )
if i check 3 check boxes then 3 values will be add in array1 but i want to add
zero at the end of the array in remaining 4 positions in array like this :
string[] array1 = {"5", "4", "2","0" ,"0","0" , "0"};
during runtime just to fix all 7 position in array ...what should i do ??
I don't get the usage of your requirement. But you can fill up the array with "0" with the following code:
List<string> list = array1.ToList();
for (int i = array1.Length; i < 7; i++)
{
list.Add("0");
}
array1 = list.ToArray();
You can do the following:
const int paddedSize = 7;
var newArray = array1.Concat(Enumerable.Repeat("0", paddedSize - array1.Length)).ToArray();
But maybe you'll understand it better without using Linq; the type you want to use is List<string> which can be dynamically resized, arrays can't. In order to get a list out of an array, you can use the linq extension:
var resized = array1.ToList();
Or
var resized = new List<string>(array1);
And now you simply add 0s until the total count of items is 7:
while (resized.Count < paddedSize)
resized.Add("0");
And back to an array:
var newArray = resized.ToArray();
I have two lists, one list have some record (not known specific no of rec, but not more than 13 records) and second list have only empty value. I am using if condition on these two list. And want to add these two list in one array. I am using this code:
for (int i=0; i>12; i++)
{
List<string> excList = new List<string>();
//added column from table, which can varies
excList.Add((string)column.ColumnName);
string[] excelList = new string[] { };
List<string> stack = Enumerable.Range(excList.Count, 13)
.Select(z => string.Empty)
.ToList<string>();
if (excList.Count > i)
{
excelList = excList.ToArray();
}
if (excList.Count <= i)
{
excelList = stack.ToArray();
}
eCol0 = excelList[0].ToString();
//show first value, after adding two list in excelList
response.Write(eCol0);
}
Using this code, when the second condition started and list (excList) is adding in array (excelList) then excelList is showing only second list data.
I want to insert these two list (excList and stack) into arrayList (which have range of 13).But these two list must add on the bases of if condition as I'm using if condition in above code.
Well you never Add something to your string array excelList. You always assign it new.
Using an array is also not the best for adding values, since you need to know beforehand the size of the array.
If you really want an array in the end with both results, you should do something like this:
List<string> excList = new List<string>();
... fill your excList here and initialize the stack list with whatever you need ...
excList.AddRange(stack);
string[] excelList = excList.ToArray();
Edit: as the comments mention, your question is a little bit confusing and you are using one big loop with no clear reason why and adding empty values makes no sence too... so i tried to get the essence out of what you wanted to know
Edit:2
Wait a second, I think you want in the end, an array of strings, with the size of 13, where the elements are at least string.empty
List<string> excList = new List<string>();
//added column from table, which can varies
excList.Add((string)column.ColumnName);
string[] excelList = new string[13];
for (int i = 0; i < excList.Count; i++)
{
excelList[i] = excList[i];
}
for (int i = excList.Count; i < 13; i++)
{
excelList[i] = string.Empty;
}
no outer loop necessary
You've written a huge amount of confusing code that could be considerably more compact.
Through th commnts I was able to understand that you have a list of N strings, where N could be between 1 and 13, and you want to turn it into an array of 13 strings with all your list items at the start, and empty strings at the end
So a list of:
"a", "b", "c"
Becomes an array of:
"a", "b", "c", "", "", "", "", "", "", "", "", "", ""
If you want a one liner to generate you a list of 13 strings, from a List x of up to 13 strings:
string[] arrayOf13 = x.AddRange(Enumerable.Repeat("", 13 - x.Count)).ToArray();
If your list x will have an unknown number more than 13:
string[] arrayOf13 = x.AddRange(Enumerable.Repeat("", 13)).Take(13).ToArray();
Or without LINQ using either a for or a while loop:
for(; x.Count < 13; x.Add(""))
string[] arrayOf13 = x.ToArray();
while(x.Count < 13)
x.Add(""));
string[] arrayOf13 = x.ToArray();
If you're willing to have the strings be null rather than empty, you can just declare an array of size 13 (all null) and then use Array.CopyTo():
string[] arrayOf13 = new string[13];
x.ToArray().CopyTo(arrayOf13, 0);
It seems your goal is to get an array of 13 strings (excelList), where each element is eigher string.Empty by default or the corresponding (same index) element from some source list (excList).
So a short-code solution would be to first create a 13-element array, initialized with 'string.Empty' and then copy the source lists elements over, limited to max 13 elements:
var excelList = Enumerable.Repeat(string.Empty, 13).ToArray();
excList.CopyTo(0, excelList, 0, Math.Min(13, excList.Count));
I have range of numeric values.
I want check each number within a range is exists in another numerics list.
I am using for loop, but it slows down my Application.
public void ShowResults()
{
// The StartNumber and EndNumber is changed depends
// upon my requirement, They are not fixed.
int StartNumber = 1 ;
int EndNumber = 1000000;
string[] list =
{
"1", "equal", "3", "perhaps", "6", "10", "378",
"1937", "28936", "26543", "937" .........,
"understood" "99993"};
for(int i = StartNumber; i<= EndNumber;i++)
{
List<int> resultList = new List<int>();
int index = Array.IndexOf(list,i.ToString());
if(index >= 0)
{
resultList.Add(i);
}
}
}
You could use binary search to find elements of one array in another, it would require one of the arrays to be sorted (the one on which you perform binary search):
string[] arr = new string[]{
"1", "equal", "3", "perhaps", "6", "10", "378",
"1937", "28936", "26543", "937",
"understood", "99993"
};
// Create sorted array
int[] firstMillionNumbers = Enumerable.Range(1, 1000000).ToArray();
// Parse out numbers only
List<int> listINT = new List<int>();
int num;
foreach (string s in arr)
if (int.TryParse(s, out num))
listINT.Add(num);
// Find elements of a list inside sorted array
List<int> resultList = new List<int>();
foreach(int num2 in listINT)
{
if (Array.BinarySearch(firstMillionNumbers, num2) >= 0)
resultList.Add(num2);
}
Try this,
if(list.Intersect(resultList).Count == resultList.Count)
{
}
trying to answer it in terms of algorithm rather than in programming language ..
you are trying to use two for loops which are causing o(n^2) complexity slowing down the program. If you have a range to compare, why not to iterate your list and check each value with two simple ifs ? this will reduce complexity to o(n) isn't it ?
There isn't much you can do with your first list, the one that goes from "1" to "1000000", since it's dynamically determined. But what about your second? If this list of string is constant, or at least generated once and early, you should use a HashSet<string> rather than a string[]. This will make lookups on it a lot faster:
// This will create an IEnumerable<string> with all numbers to search.
IEnumerable<string> stringsToFind = Enumerable.Range<int>(StartNumber, EndNumber-StartNumber).Select(number => number.ToString());
// This is all the strings in a HashSet. This should be done *beforehand*.
HashSet<string> strings = new HashSet<string>(new [] { "1", "equal", "3", etc...};
// resultList contains all numbers (from stringToFind) that are in strings).
var resultList = strings.Intersect(stringsToFind);
In general, iterating over a large set of variables will always be slow. There's no real way around it other than indexing or sorting (e.g. in a tree, so you're able to skip large parts of it).
However, your example code is slowed down even more due to you recreating a new List<int> once every iteration (something you probably don't want to do, as your results won't make any sense that way).
First you need to have to similar collections (with the same type numeric or string). Than you should select smaller collection and adoptate it to second collection. In example below I assume that list collection will be smaller than collection with numbers.
I don't know will it be good or not solution.
var originalNumbers = new[] {1, 2, 3, 4, 5, 6};
string[] list =
{
"1", "equal", "3", "perhaps", "6", "10", "378",
"1937", "28936", "26543", "937", "understood", "99993"
};
IList<int> parsedNumbers = new List<int>();
foreach (var item in list)
{
int temp;
if(int.TryParse(item, out temp))
parsedNumbers .Add(temp);
}
var result = parsedNumbers .Intersect(originalNUmbers);
Several problems with the question. Why would you create resultList a million times (and it will only have the last value)? Why are you calling i.ToString a million times rather than filtering the small list to int?
OK I know you are going to say this is not the real problem. And my response is that is the posted problem. If you want realistic answers you need realistic questions.
int StartNumber = 1 ;
int EndNumber = 1000000;
string[] list =
{
"1", "equal", "3", "perhaps", "6", "10", "378",
"1937", "28936", "26543", "937" .........,
"understood" "99993"};
List<int> resultList = new List<int>();
int intOut;
foreach(string li in list)
{
if (int32.TryParse(li, out intOut))
{
if(intOut >= StartNumber && intOut <= EndNumber) resultList.Add(intOut));
}
}
I have a CSV file that has rows, where data for some columns only appear in one of those rows, with other columns repeating their value:
Heading1, Heading2, Heading3, Heading4
1 , 2 , , 4
1 , , 3 , 4
How can I end up with:
Heading1, Heading2, Heading3, Heading4
1 , 2 , 3 , 4
I want to group on Heading1 and Heading4 as they are unique to the repeated rows and get the first non-blank value for all other rows, ending up with a single string[].
I've got as far as grouping on new { Header1, Header4 } to get a group of rows, but I'm having a hard time turning that into something where I can select the first non null value for each column, then turning it back into a single row (string[]).
Ideally I'd like a function that works with any number of columns as in the actual file there are a large number.
It can be done with LINQ using Aggregate. Create a function to compare the running totals with the current row, setting the total for the column to the current value for the column if the total is not empty and the current value is not empty.
[TestMethod]
public void MergeArrays() {
string[] Input = new[] {
"H1, H2, H3, H4",
"1,2,,4",
"1,,3,4"
};
var header = Input.ElementAt(0) ;
var aggregation = string.Join(",", Input.Skip(1).Select(ln => ln.Split(',')).Aggregate(new[] { "", "", "", "" }, Agg));
var result = new string[] { header, aggregation };
Assert.AreEqual("H1, H2, H3, H4", header);
Assert.AreEqual("1,2,3,4", aggregation);
}
private static string[] Agg(string[] aggregation, string[] input) {
for (var idx = 0; idx < aggregation.GetLength(0); idx++) {
if (aggregation[idx] == string.Empty &&input[idx] != string.Empty){
aggregation[idx] = input[idx];
}
}
return aggregation;
}
hth,
Alan.
Make an array of length 4 with values initialized to some to empty strings (or zeros as appropriate).
For each non-header row, loop over the fields, storing the value in the corresponding array position whenever the field value is not blank.
Write-out the values in the array to the new CSV file.