Shift elements in string array to left to fill 'holes' - c#

I have a list of names and phone numbers like so:
var phonelist = List<string[]>
{
new string[] {"Bill", "1234", "12345", "12314" },
new string[] {"Bob", "", "12345", "12314" },
new string[] {"Chris", "", "", "12314" },
new string[] {"Dave", "1234", "", "12314" },
new string[] {"Andy", "1234", "12345", "" },
}
What is the most efficient/elegant way to process this list so that the 'empty' numbers get filled from the right ?
Note, the arrays should stay the same length, like so:
var phonelist = List<string[]>
{
new string[] {"Bill", "1234", "12345", "12314" },
new string[] {"Bob", "12345", "12314", "" },
new string[] {"Chris", "12314", "", "" },
new string[] {"Dave", "1234", "12314", "" },
new string[] {"Andy", "1234", "12345", "" },
}

for each array cell, check if its empty and swap it with cell+1, if it's still empty swap it with cell+2.. when cell becomes not empty do the same thing with cell+2...
int j;
foreach (string[] strs in phoneList)
{
for (int i = 0; i < strs.Length; i++)
{
j = 1;
while (string.IsNullOrEmpty(strs[i]) && j < strs.Length - i)
{
if (!string.IsNullOrEmpty(strs[i + j])) // to not swap 2 empty strings
{
strs[i] = strs[i + j];
strs[i + j] = "";
}
j++;
}
}
}

public static void PutEmptyStringsToTheEnd(string[] array) {
int j = 0;
for (int i = 0; i < array.Length; ++i)
if (array[i].Length > 0)
array[j++] = array[i];
while (j < array.Length)
array[j++] = "";
}
Call this function for each List element.

simple and ugly :(
for(var x=0;x<phonelist.Count;x++)
{
var strings = phonelist[x];
var l = strings.Length;
var newAr=new string[l];
var k = 0;
for (var i = 0; i < l; )
{
if(strings[i]!="")
{
newAr[k++] = strings[i];
}
i++;
}
for (; k < l; k++)
newAr[k] = "";
phonelist[x] = newAr;
}

You could do something like that :
Comparison<string> comparison = (x,y) =>
{
if (String.IsNullOrEmpty(x))
return 1;
if (String.IsNullOrEmpty(y))
return -1;
return String.Compare(x,y);
}
foreach (string[] array in phoneList)
{
Array.Sort(array, comparison);
}
However you will need to tune the comparison logic a bit to keep the names before the numbers
EDIT : since the name seems to always be the first element, another option is to exclude it from the sort. No Array.Sort overload takes a Comparison<T> and a range, so you have to use a IComparer<T> instead :
class MyComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (String.IsNullOrEmpty(x))
return 1;
if (String.IsNullOrEmpty(y))
return -1;
return String.Compare(x,y);
}
}
foreach (string[] array in phonelist)
{
Array.Sort(array, 1, array.Length - 1, new MyComparer());
}

This should work. I'm not that knownledged at C#, but the idea is there
foreach(string[] person in phonelist)
{
string[] newPerson = {"","","",""};
int index = 0;
for(int i=0; i<4; i++)
{
if(!String.IsNullOrEmpty(person[i])) newPerson[index++] = person[i];
}
person = newPerson;
}

This is cooler
List<string[]> result = phonelist.Select(per => per.OrderBy(txt=>txt.Length==0).ToArray()).ToList();

List<string[]> sorted = new List<string[]>();
foreach (string[] entry in phoneList)
{
List<string> nonEmpty = (from s in entry
where String.IsNullOrEmpty(s) == false
select s).ToList();
int pad = entry.Length - nonEmpty.Count;
List<string> pads = new List<string>();
while (pad > 0)
{
pads.Add(String.Empty);
--pad;
}
List<string> sortedEntry = new List<string>();
sortedEntry.AddRange(nonEmpty);
sortedEntry.AddRange(pads);
sorted.Add(sortedEntry.ToArray());
}

Related

how to get first,second ... values of two string lists inside an array list?

I have a problem retrieving values in the order that I want
I wrote a simple code to demonstrate :
List<string> st1 = new List<string>() {"st11","st12"};
List<string> st2 = new List<string>() {"st21","st22"};
ArrayList stringArrayList = new ArrayList();
stringArrayList.Add(st1);
stringArrayList.Add(st2);
string[] n1 = new string[10];
int i = 0;
foreach (List<string> item in stringArrayList)
{
foreach (var item2 in item)
{
n1[i] = item2;
i++;
}
}
in this code the output will be : st11,st12 st21,s22
i want it to get values like this : st11,st21 st12,st22
i want the information stored in this order "st11,st21 st12,st22" into n1
If the lenght of the list are the same you can make something like this:
int j = 0;
int lengthToLoop = st1.length;
for(int i = 0; i < lengthToLoop; i++)
{
n1[j++] = st1[i];
n1[j++] = st2[i];
}
If the length are not equal you can calculate the minimum, copy the minimum length of element from each and then copy the remaining.
Here's an implementation that will do what you're looking for, and will also handle jagged arrays.
List<string> st1 = new List<string>() { "st11", "st12" };
List<string> st2 = new List<string>() { "st21", "st22", };
ArrayList stringArrayList = new ArrayList();
stringArrayList.Add(st1);
stringArrayList.Add(st2);
//this will protect us against differing max indexes if the 2D array is jagged.
int maxIndex = 0;
int totalElements = 0;
foreach (List<string> currentList in stringArrayList)
{
if (currentList.Count > maxIndex)
{
maxIndex = currentList.Count;
}
totalElements += currentList.Count;
}
string[] n1 = new string[totalElements];
int i = 0;
for (int j = 0; j < maxIndex; j++)
{
for (int k = 0; k < stringArrayList.Count; k++)
{
List<string> currentStringArray = (List<string>)stringArrayList[k];
if (j < currentStringArray.Count)
{
n1[i] = currentStringArray[j];
i++;
}
}
}
You have to reverse the two loops, making the outer loop the inner loop.
Use a for loop instead of a foreach loop for the outer loop using the length of the string arrays as the delimiter.
Also: Don't use ArrayList, but a real typed list.
List<string> st1 = new List<string>() { "st11", "st12" };
List<string> st2 = new List<string>() { "st21", "st22" };
List<List<string>> stringArrayList = new List<List<string>>();
stringArrayList.Add(st1);
stringArrayList.Add(st2);
// Get length of first string array
int firstArrayLength = stringArrayList[0].Count;
string[] n1 = new string[10];
int i = 0;
// For each position in the arrays from 0 to firstArrayLength -1 do
for (int arrayPosition = 0; arrayPosition < firstArrayLength; arrayPosition++)
{
// For each of the string array
foreach (var stringArray in stringArrayList)
{
// Get the item from the stringArray at position arrayPosition
n1[i] = stringArray[arrayPosition];
i++;
}
}
First, check the max list length, and then take item at index (0,1,3... till max) from every list. Don't forget to check if the index exist. In addition, you can set the exact size of n1 because it is the sum of all list count. You don't need to have a separated line for i++ in this case.
List<string> st1 = new List<string> { "st11", "st12" };
List<string> st2 = new List<string> { "st21", "st22" };
List<List<string>> stringArrayList = new List<List<string>> {st1, st2};
int maxCount = stringArrayList.Max(x => x.Count);
int totalItems = 0;
stringArrayList.ForEach(x=> totalItems+= x.Count);
string[] n1 = new string[totalItems];
int i = 0;
for (int index = 0; index < maxCount; index++)
{
foreach (var list in stringArrayList)
{
if (list.Count > index)
{
n1[i++] = list[index];
}
}
}

Arrange strings in alphabetical order

//code with problem (maybe)
numberArray = NameNumEquv;
listStringArray = NamesArray;
string[] sortedArray = new string[NamesArray.Length];
for (int arrayItemCounter = 0; arrayItemCounter < NamesArray.Length; arrayItemCounter++)
{
compareArrayCount = 1;
initialArrayCount = 0;
while (compareArrayCount < numberArray.Length)
{
for (int doubleArrayLength = 0; doubleArrayLength < numberArray[compareArrayCount].Length; doubleArrayLength++)
{
if (numberArray[initialArrayCount][doubleArrayLength] < numberArray[compareArrayCount][doubleArrayLength])
{
initialArrayCount = compareArrayCount;
break;
}
}
compareArrayCount = compareArrayCount + 1;
}
sortedArray[arrayItemCounter] = listStringArray[initialArrayCount];
List<string> tempArrayValues = new List<string>();
List<int[]> tempNumArrayValues = new List<int[]>();
for (int tempArrayCount = 0; tempArrayCount < listStringArray.Length; tempArrayCount++)
{
if (tempArrayCount != initialArrayCount)
{
tempArrayValues.Add(listStringArray[tempArrayCount]);
tempNumArrayValues.Add(numberArray[tempArrayCount]);
}
}
listStringArray = tempArrayValues.ToArray();
numberArray = tempNumArrayValues.ToArray();
tempArrayValues.Clear();
tempNumArrayValues.Clear();
}
//till here
foreach (string nums in sortedArray)
{
Console.WriteLine(nums);
}
}
public static int[] AlphaNumericConversion(string stringValue, int arrayLength)
{
string Alphabets = "abcdefghijklmnopqrstuvwxyz";
char[] alphabetArray = Alphabets.ToCharArray();
string lowerCaseConv = stringValue.ToLower();
char[] stringArray = lowerCaseConv.ToCharArray();
int[] numericalConvertedArray = new int[arrayLength];
for (int valueArrayCount = 0; valueArrayCount < numericalConvertedArray.Length; valueArrayCount++)
{
numericalConvertedArray[valueArrayCount] = 0;
}
for (int letterCounter= 0;letterCounter < stringArray.Length;letterCounter++)
{
for (int alphabetCounter = 0; alphabetCounter < Alphabets.Length; alphabetCounter++)
{
if (stringArray[letterCounter] == alphabetArray[alphabetCounter])
numericalConvertedArray[letterCounter] = alphabetCounter + 1;
}
}
return numericalConvertedArray;
}
}
}
I want to arrange strings in ascending order. It is arranging the single letter strings(a, b, c,d, e.....) in reverse alphabetical order as in Z-A and string containing 2 or more letters randomly such as "Aayush", "Ayush", "Aayusha", "Ayusha" to "Aayusha","Ayusha","Aayush","Ayush". What is wrong with the code. Don't suggest to simply use List.Sort() because I want to write it in algorithmic manner. I'm trying to understand how it works rather than using Sort().

how to remove a row from an 2-D Array

I meet a problem that I don't know how to solve it. I created an 2-D array which contains Date and price.I want to delete the row whose datetime is between two date.The example below, I want to delete the third row.
Date Price
01/07 10
02/07 20
Empty 30
03/07 40
Here is my code:(I dont know why it does work)
for (int i=0;i<row.length;i++)
{
for (int j=0;j<col.length;j++)
{
if (Array[row,0]=" ")
{
Array[row,j]=Array[row+1,j];
i++
}
}
}
If I were you I would create an object and store Date and Price as a properties.
For example:
public class DateAndPrice //let this name be whatever you want
{
public DateTime Date { get; set; }
public int Price { get; set; }
}
Then, store them in a List so you can easily remove them with the Remove method.
List<DateAndPrice> list = new List<DateAndPrice>();
If you are hell-bound on using arrays, you can use a Linq query to filter out the results and return a new array:
var data = new[] {
new { Date = "01/07", Price = 10 },
new { Date = "02/07", Price = 20 },
new { Date = "", Price = 30 },
new { Date = "03/07", Price = 40 }
};
var noBlanks = (from d in data
where !string.IsNullOrWhiteSpace(d.Date)
select d).ToArray();
Which will select the data that does not have empty, null, or whitespace date items and place them in a new array.
If you're dead set on staying with a non-List like 2D array, you can try the following:
string[,] array =
{
{ "01/07", "10" },
{ "02/07", "20" },
{ String.Empty, "30" },
{ "03/07", "40" },
};
array = RemoveEmptyDates(array);
for (int i = 0; i <= array.GetUpperBound(0); i++)
{
for (int j = 0; j <= array.GetUpperBound(1); j++)
{
Console.Write("{0} \t", array[i, j]);
}
Console.WriteLine();
}
RemoveEmptyDates looks like:
public static string[,] RemoveEmptyDates(string[,] array)
{
// Find how many rows have an empty date
int rowsToRemove = 0;
for (int i = 0; i <= array.GetUpperBound(0); i++)
{
if (string.IsNullOrEmpty(array[i, 0]))
{
rowsToRemove++;
}
}
// Reinitialize an array minus the number of empty date rows
string[,] results = new string[array.GetUpperBound(0) + 1 - rowsToRemove, array.GetUpperBound(1) + 1];
int row = 0;
for (int i = 0; i <= array.GetUpperBound(0); i++)
{
int col = 0;
if (!string.IsNullOrEmpty(array[i, 0]))
{
for (int j = 0; j <= array.GetUpperBound(1); j++)
{
results[row, col] = array[i, j];
col++;
}
row++;
}
}
return results;
}
Results:
01/07 10
02/07 20
03/07 40
Your approach to this is not the best. You should be creating a helper class:
public class DatePrice
{
public DateTime Date { get; set; }
public decimal Price { get; set; }
}
Then creating a collection class:
var prices = new List<DatePrice>();
Then you can add data like this:
prices.Add(new DatePrice() { Date = DateTime.Now, Price = 10m });
And you can easily remove an item based on an index like this:
prices.RemoveAt(2);
If you really must use an array, you'll need an extension method, such as this to remove an item (copied from here):
public static T[] RemoveAt<T>(this T[] source, int index)
{
T[] dest = new T[source.Length - 1];
if( index > 0 )
Array.Copy(source, 0, dest, 0, index);
if( index < source.Length - 1 )
Array.Copy(source, index + 1, dest, index, source.Length - index - 1);
return dest;
}
For 2-dimensional arrays, use this:
string[][] a = new string[][] {
new string[] { "a", "b" } /*1st row*/,
new string[] { "c", "d" } /*2nd row*/,
new string[] { "e", "f" } /*3rd row*/
};
int rowToRemove = 1; // 2nd row
a = a.Where((el, i) => i != rowToRemove).ToArray();

concatenate items in N lists

I have string of items as - string item = "a,b,c+1,2,3,4+z,x";
I split this string with + and add to N number of lists as
List keysList = item.Split('+').ToList()
From this lists I expect to create keys as
a1z
a1x
a2z
a2x
a3z
a3x etc:-
I have tried below block of code . but something is not correct here
private string GetValue(List<string> keysList, int i, int keyCount, string mainKey)
{
List<string> tempList = keysList[i].Split(',').ToList();
foreach (string key in tempList)
{
mainKey += key;
i++;
if (i == keyCount)
{
return mainKey;
}
GetValue(keysList, i, keyCount, mainKey);
}
return mainKey;
}
Here's one way to do it...
string item = "a,b,c+1,2,3,4+z,x";
var lists = item.Split('+').Select(i => i.Split(',')).ToList();
IEnumerable<string> keys = null;
foreach (var list in lists)
{
keys = (keys == null) ?
list :
keys.SelectMany(k => list.Select(l => k + l));
}
Fiddle
You can create helper function as follows:
static IEnumerable<string> EnumerateKeys(string[][] parts)
{
return EnumerateKeys(parts, string.Empty, 0);
}
static IEnumerable<string> EnumerateKeys(string[][] parts, string parent, int index)
{
if (index == parts.Length - 1)
for (int col = 0; col < parts[index].Length; col++)
yield return parent + parts[index][col];
else
for (int col = 0; col < parts[index].Length; col++)
foreach (string key in EnumerateKeys(parts, parent + parts[index][col], index + 1))
yield return key;
}
Usage demo:
string[][] parts = {
new[] { "a", "b", "c" },
new[] { "1", "2", "3", "4" },
new[] { "z", "x" }
};
foreach (string key in EnumerateKeys(parts))
Console.WriteLine(key);
Online demo: http://rextester.com/HZR27388

Wrong number of indices inside []; expected '1'

I have the following array:
string[] list1 = new string[2] { "01233", "THisis text" };
string[] list2 = new string[2] { "01233", "THisis text" };
string[] list3 = new string[2] { "01233", "THisis text" };
string[] list4 = new string[2] { "01233", "THisis text" };
string[][] lists = new string[][] { list1, list2, list3, list4 };
I am trying to see the array values using the following code:
for (int i = 0; i < lists.GetLength(0); i++)
{
for (int j = 0; j < lists.GetLength(1); j++)
{
string s = lists[i, j]; // the problem is here
Console.WriteLine(s);
}
}
Console.ReadLine();
The problem is lists[i, j]; is underlined and causing this error message : Wrong number of indices inside []; expected '1'
Could you please tell me how to solve this problem ?
lists is not a 2D array. It is an array of arrays. Hence the syntax lists[i][j].
for (int i = 0; i < lists.Length; i++)
{
for (int j = 0; j < lists[i].Length; j++)
{
string s = lists[i][j]; // so
Console.WriteLine(s);
}
}
Console.ReadLine();
Note how Length is checked for an array of arrays. However, as others have said, why not use foreach? You need two nested foreach loops for an array of arrays.
Another option is to actually use a 2D array, a string[,]. Declared like:
string[,] lists = { { "01233", "THisis text" },
{ "01233", "THisis text" },
{ "01233", "THisis text" },
{ "01233", "THisis text" }, };
Then you can use two for loops like you have, with lists[i,j] syntax, or one single foreach.
Because you have list of lists and not 2D array. To get element from your datastructure you have to use it like this:
lists[i][j]
and your full code would be:
for (int i = 0; i < lists.Length; i++)
{
for (int j = 0; j < lists[i].Length; j++)
{
string s = lists[i][j];
Console.WriteLine(s);
}
}
Console.ReadLine();
But actually, in your case it's better to use foreach:
foreach (var l in lists)
{
foreach (var s in l)
{
Console.WriteLine(s);
}
}
Console.ReadLine();
Try to use this
for (int i = 0; i < lists.Length; i++)
{
for (int j = 0; j < lists[i].Length; j++)
{
string s = lists[i][j];
Console.WriteLine(s);
}
}
Console.ReadLine();
Use foreach instead
foreach(var array in lists )
foreach(var item in array)
{
//item
}

Categories

Resources