I'll just go straight to the point. I want to move the items in an array in a uniform difference, let's say I have this.
string[] fruits = { "Banana", "Apple", "Watermelon", "Pear", "Mango" };
For example, let's say I want to remove the "Apple" so I'll do this.
fruits[1] = "";
Now all that left are:
{ "Banana", "", "Watermelon", "Pear", "Mango" }
How do I really remove the Apple part and get only:
{ "Banana", "Watermelon", "Pear", "Mango" }
Note that the index of all the items from "Watermelon" until the end of the array moves 1 backward. Any ideas?
The List class is the right one for you. It provides a method Remove which automatically moves the following elements backwards.
If you really want to use Arrays, you can use Linq to filter your list and convert to array:
string[] fruits = { "Banana", "Apple", "Watermelon", "Pear", "Mango" };
fruits = fruits.Where(f => f != "Apple").ToArray();
If you're not required to use an array, look at the List class. A list allows items to be added and removed.
Similar to Wouter's answer, if you want to remove by item index rather than item value, you could do:
fruits = fruits.Where((s, i) => i != 1).ToArray();
You can do something like this:
for( int i = 1; i + 1 < fruits.Length; i++ )
fruits[i] = fruits[i + 1];
fruits = System.Array.Resize( fruits, fruits.Length - 1 );
If you do not care about the order of the fruit in the array, a smarter way to do it is as follows:
fruits[1] = fruits[fruits.Length - 1];
fruits = System.Array.Resize( fruits, fruits.Length - 1 );
I think one of the most useful things a new programmer can do is study and understand the various collection types.
While I think the List option that others have mentioned is probably what you are looking for, it's worth looking at a LinkedList class if you are doing a lot of insertions and deletions and not a lot of looking up by index.
This is an example of how I used lists and arrays to remove an item from an array. Note I also show you how to use linq to search an array full of bad names to remove. Hope this helps someone.
public static void CheckBadNames(ref string[] parts)
{
string[] BadName = new string[] {"LIFE", "ESTATE" ,"(",")","-","*","AN","LIFETIME","INTREST","MARRIED",
"UNMARRIED","MARRIED/UNMARRIED","SINGLE","W/","/W","THE","ET",
"ALS","AS", "TENANT" };
List<string> list = new List<string>(BadName); //convert array to list
foreach(string part in list)
{
if (BadName.Any(s => part.ToUpper().Contains(s)))
{
list.Remove(part);
}
}
parts = list.ToArray(); // convert list back to array
}
As a beginner 3 years ago, I started making the software that I'm still working on today. I used an array for 'PartyMembers' of the game, and I'm basically today regretting it and having to spend a ton of time converting all this hard coded $#!t into a list.
Case in point, just use Lists if you can, arrays a nightmare in comparison.
Related
I have 2 lists. One contains search element, one contains the data.
I need to loop for each element in list2 which contains any string in list1 ("cat" or "dog"). For examples:
List<string> list1 = new List<string>();
list1.Add("Cat");
list1.Add("Dog");
list1.Add... ~1000 items;
List<string> list2 = new List<string>();
list2.Add("Gray Cat");
list2.Add("Black Cat");
list2.Add("Green Duck");
list2.Add("White Horse");
list2.Add("Yellow Dog Tasmania");
list2.Add("White Horse");
list2.Add... ~million items;
My expect is listResult: {"Gray Cat", "Black Cat", "Yellow Dog Tasmania"} (because it contains "cat" and "dog" in list1). Instead of nested looping, do you have any idea to make the sequence run faster?
My current solution as below. But...it seems too slow:
foreach (string str1 in list1)
{
foreach (string str2 in list2)
{
if str2.Contains(str1)
{
listResult.Add(str2);
}
}
}
An excellent use case for parallelization!
Linq approach without parallelization (equals internally your approach beside the fact that the internal loop breaks if one match was found - your approach also searches for other matches)
List<string> listResult = list2.Where(x => list1.Any(x.Contains)).ToList();
Parallelized the loop with AsParallel() - if you have a multicore system there will be a huge performance improvement.
List<string> listResult = list2.AsParallel().Where(x => list1.Any(x.Contains)).ToList();
Runtime comparison:
(4 core system, list1 1000 items, list2 1.000.000 items)
Without AsParallel(): 91 seconds
With AsParallel(): 23 seconds
The other way with Parallel.ForEach and a thread safe result list
System.Collections.Concurrent.ConcurrentBag<string> listResult = new System.Collections.Concurrent.ConcurrentBag<string>();
System.Threading.Tasks.Parallel.ForEach<string>(list2, str2 =>
{
foreach (string str1 in list1)
{
if (str2.Contains(str1))
{
listResult.Add(str2);
//break the loop if one match was found to avoid duplicates and improve performance
break;
}
}
});
Side note: You have to iterate over list2 first and break; after match, otherwise you add items twice: https://dotnetfiddle.net/VxoRUW
Contains will use a 'naive approach' to string searching. You can improve on that by looking into string search algorithms.
One way to do this could be to create a generalized Suffix tree for all your search words. Then iterate through all the items in your list2 to see if they match.
Still, this might be overkill. You can first try with some simple optimizations as proposed by fubo to see if that's fast enough for you.
The List string is not a suitable data structure for solving this problem efficiently.
What you are looking for is a Trie or Dawg, to sort every word from your original dictionary list1.
The aim is for every letter of word from list2, you will only have 0-26 check.
With this datastructure instead of reading a big list of word till you find one, you will be looking for word like in a paper dictionary. And that should be faster. Application that look for all word from a language in a text use this principle.
Since it seems you want to match entire words, you can use a HashSet to do a more efficient search and prevent iterating list1 and list2 more than once.
HashSet<string> species =
new HashSet<string>(list1);
List<string> result = new List<string>();
foreach (string animal in list2)
{
if (animal.Split(' ').Any(species.Contains))
result.Add(animal);
}
If I run this (with list1 containing 1000 items and list2 containing 100,000 items) on a 4 core laptop:
The algorithm in the question: 37 seconds
The algorithm using AsParallel: 7 seconds
This algorithm: 0.17 seconds
With 1 million items in list2 this algorithm takes about a second.
Now while this approach does work, it might produce incorrect results. If list1 contains Lion then a Sea lion in list2 will be added to the results even if there is none in list1. (If you use a case insensitive StringComparer in the HashSet as suggested below.)
To solve that problem, you would need some way to parse the strings in list2 into a more complex object Animal. If you can control your input, that may be a trivial task, but in general it is hard. If you have some way of doing that, you can use a solution like the following:
public class Animal
{
public string Color { get; set; }
public string Species { get; set; }
public string Breed { get; set; }
}
And then search the species in a HashSet.
HashSet<string> species = new HashSet<string>
{
"Cat",
"Dog",
// etc.
};
List<Animal> animals = new List<Animal>
{
new Animal {Color = "Gray", Species = "Cat"},
new Animal {Color = "Green", Species = "Duck"},
new Animal {Color = "White", Species = "Horse"},
new Animal {Color = "Yellow", Species = "Dog", Breed = "Tasmania"}
// etc.
};
var result = animals.Where(a => species.Contains(a.Species));
Note that the string search in the HashSet is case sensitive, if you do not want that you can supply a StringComparer as constructor argument:
new HashSet<string>(StringComparer.CurrentCultureIgnoreCase)
Pre-information
-User inputs data in console
-Save data in an Array of 2 elements[2]
-Save the Array with 2 elements in a LIST
*Now what i try to achieve is that the user can check if search is in the list regardless if its written in lower or upper case.
List<string[]>MyList = new List<string[]>();
var[] myArray = new [] { "A", "B" };
MyList.Add(myArray);
int y = 0;
Console.WriteLine("Inpu what you are Searching For: ");
string serchString = Console.ReadLine();
serchString = serchString.ToLower();
for (int i = 0; i < MyList.Count; i++)
{
List<object> oneTimeList = new List<object>();
oneTimeList.AddRange(myList[i]);
Console.WriteLine(oneTimeList);
if (MyList[i].Contains(serchString.ToLower()))
{
Console.WriteLine("Yes you have added this");
}
else if (!myList[i].Contains(serchString))
{
y += 1;
}
}
if (y == myList.Count)
{
Console.WriteLine("You Have not entered this Yet");
}
My logic(maybe not the best in the planet :P) says that i have to make a comparison of all the elements of the array in turn with the search the user made and if its true continue, And in order to make this i need first to get the information of the arrays of the list and convert them to a list and then convert them to lowercase.
Every thing goes fine until the part where i try to add the Arrays to the List and all i am adding are Arrays[].
Any Suggestion on how to approach this issue or how to pass the elements of an ARRAY that is inside of a LIST to a NEW LIST?
It sounds like to want to take an array of strings (assumed as you mention lower casing it), add them all to a list, lower-case them and then compare?
This being the case you don't need to do any of that. You can simply do:
var myArray = new [] { "A", "B", "C" }
var toCheck = "a";
//Use the IEnumerable<T>.Contains() Linq extension
if (myArray.Contains(toCheck, StringComparer.OrdinalIgnoreCase))
{
//...
}
If you really want to add them to a list I can't give you an example using your code, but to "pass elements of an array to a new list" you can do any of the following:
//List<T>(IEnumerable<string>) constructor
var newList = new List<string>(myListOfStrings);
//List<T>.AddRange(IEnumerable<string>)
var newList = new List<string>();
newList.AddRange(myListOfStrings);
//List<T>.Add(T) (adding items one at a time)
var newList = new List<string>();
newList.Add(myListOfStrings[index]);
It's worth noting here as well that any of the above references to myListOfStrings could be an array of strings (string[]) or a list of strings (List<string>) because they both implement IEnumerable<string> which is the type the above methods require (except for Add which wants a single item).
Here is the documentation for List that describes in details how to use each of the above (and all other other available methods...)
Say I have
List<int> ages = new List<int>() { 8, 5, 3, 9, 2, 1, 7 };
List<int> marks = new List<int>() { 12, 17, 08, 15, 19, 02, 11 };
I can sort my marks by ages like this:
while (true)
{
bool swapped = false;
for (int i = 0; i < ages.Count - 1; i++)
if (ages[i] > ages[i + 1])
{
int tmp = ages[i];
ages[i] = ages[i + 1];
ages[i + 1] = tmp;
tmp = marks[i];
marks[i] = marks[i + 1];
marks[i + 1] = tmp;
swapped = true;
}
if (!swapped)
break;
}
Now I want to put this into a function that accepts any two lists. The first parameter will be the reference list, the numerical or comparable list. The second parameter will be the list containing the data.
For example:
public static void Sort<T>(List<T> RefList, List<T> DataList)
{
// sorting logic here...
}
There are a few problems:
First of all, T is almost certainly not the same type in RefList and DataList. RefList might be dates, integers, or doubles; whereas DataList is free to be absolutely anything. I need to be able to receive two, arbitrary generic types.
Secondly, I cannot seem to use the > operator with the T in this line:
if (ages[i] > ages[i + 1])
Perhaps my whole approach is wrong.
By the way, I have read responses to similar questions that suggest that the two lists should be combined into a single list of a compound data type. This isn't practical at all for my application. All I want to do is write a static function that somehow sorts one list based on the elements of another.
To sort one list the way you want you actually need to somehow keep references from items in first list to they weight/keys in the second list. No existing methods do that as you can't easily associate metadata with arbitrary values (i.e. if first list is list of int as in your case there is nothing to map to keys in second list). Your only reasonable option is to sort 2 lists at the same time and make association by index - again no existing classes to help.
It may be much easier to use solution that you reject. I.e. simply Zip and OrderBy, than recreate first list:
ages = ages
.Zip(marks, (a,m)=> new {age = a; mark = m;})
.OrderBy(v => v.mark)
.Select(v=>v.age)
.ToList();
Note (courtesy of phoog): if you need to do this type of sorting with Array there is Array.Sort that allows exactly this operatiion (see phoog's answer for details).
There's no framework method to do this with List<T>, but if you don't mind putting the data into two arrays, you can use one of the Array.Sort() overloads that takes two arrays as arguments. The first array is the keys, and the second is the values, so your code might look like this (leaving aside the step of getting arrays from the lists):
Array.Sort(ages, marks);
The specifics of getting the values into arrays and then back into lists would depend, among other things, on whether you need to end up with the same list sorted appropriately or whether it's okay to return a new list with the data in the desired order.
Use:
public static void Sort<TR, TD>(IList<TR> refList, IList<TD> dataList)
where TR : System.IComparable<TR>
where TD : System.IComparable<TD>
{
...
}
and then use:
refList[i].CompareTo(refList[i+1])
instead of the operators.
.Net numbers already implement IComparable, and you can use overloads that allow you to specify a different IComparable.
If I understand "I can sort my marks by ages like this:" properly,
I would like to suggest the below to eliminate much confusion.
struct Student{
int age;
int marks;
};
List<Student> students = {{8,12}, ...};
Now you can sort according to age and marks is accordingly sorted automatically.
If it is not possible, you need to fix the code as below.
First of all, T is almost certainly not the same type in RefList and DataList.
Then you need 2 parameters T1, T2. Just T implies the types are the same.
public static void Sort<RefType, DataType>(List<RefType> RefList, List<DataType> DataList)
{
You can also zip the two lists together as suggested by Mechanical Snail and explained in Looping through 2 Lists at once
I just want get a 2 dimension array of List in c#. In my thought, below should works but it didn't, the 1 dimension array of List works. I use Unity3D with Mono, however I think it's language related problem.
List<MyType>[,] twoDArrayofList;//don't work, it's type is List<MyType>
List<MyType>[] oneDArrayofList;//it's works, the type is List<MyType>
Anyone know what's wrong? Thank you.
What do you mean by "doesn't work"? What error are you getting?
I don't know about Mono (or Unity3D), but I just tried the following in a .NET project and got the results I expected:
List<string>[,] strings = new List<string>[2, 2];
strings[0, 0] = new List<string> { "One" };
strings[0, 1] = new List<string> { "Two" };
strings[1, 0] = new List<string> { "Three" };
strings[1, 1] = new List<string> { "Four" };
This is an older post, but it came up in my search for a similar answer. I found that creating a Dictionary instead of a List meets my needs. You can't iterate by index, but if you have a discrete list and you are iterating through the first string "Key", you can easily obtain the second string "Value".
Here is a stackoverflow post with examples:
What is the best way to iterate over a Dictionary in C#?
I have string containing n elements.
I want to insert a automatically incremented number to the first position.
E.g
Data
66,45,34,23,39,83
64,46,332,73,39,33
54,76,32,23,96,42
I am spliting to string to array with split char ','
I want resultant array with a incremented number a first position
1,66,45,34,23,39,83
2,64,46,332,73,39,33
3,54,76,32,23,96,42
Please suggest how can I do it.
Thanks
You can't with an array, you need to use a List<string> instead.
For example:
List<string> words = new string[] { "Hello", "world" }.ToList();
words.Insert(0, "Well");
Linq has an easy way to accomplish your "mission":
First add the correct namespace:
using System.Linq;
And then:
// Translate your splitted string (array) in a list:
var myList = myString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
// Where insertPosition is the position you want to insert in:
myList.Insert(insertingPosition, insertedString);
// Back to array:
string[] myArray = myList.ToArray<string>();
Hope this helps...
You cannot insert anything to Array. Use List<T> instead.
You have to use something like an ArrayList instead, which has an ArrayList.Insert() method.
ArrayList myAL = new ArrayList();
myAL.Insert( 0, "The" );
myAL.Insert( 1, "fox" );
myAL.Insert( 2, "jumps" );
myAL.Insert( 3, "over" );
myAL.Insert( 4, "the" );
myAL.Insert( 5, "dog" );
well what if you have the list like the following
string a="66,45,34,23,39,83";
string b="64,46,332,73,39,33";
string c="54,76,32,23,96,42";
before splitting a,b,c...
string[] s=new string[]{a,b,c};
for(int i=0; i<s.length;i++){
s[i]=(i+1)+s[i];
}
now split each string in s
you will have a list like
1,66,45,34,23,39,83
2,64,46,332,73,39,33
3,54,76,32,23,96,42
I am not sure if I have understood your problem or not. :|
I know you want a C# answer (and there are good answers here already in that language), but I'm learning F# and took this on in that language as a learning exercise.
So, assuming you want an array of strings back and are willing to use F#...
let aStructuredStringArray = [|"66,45,34,23,39,83"
"64,46,332,73,39,33"
"54,76,32,23,96,42"|]
let insertRowCountAsString (structuredStringArray: string array) =
[| for i in [0 .. structuredStringArray.Length-1]
do yield String.concat "" [ i.ToString(); ","; structuredStringArray.[i]]
|]
printfn "insertRowCountAsString=%A" (insertRowCountAsString aStructuredStringArray)
C# arrays cannot be resized. This means that you can't insert items.
You have two options:
Use a List<T> instead.
Create a new array, with one extra item in, copy the contents of the old one across and so on.
Option 1 is invariably to be preferred.
There is Array.Resize(T). On the face of it this contradicts what I state above. However, the documentation for this method states:
This method allocates a new array with the specified size, copies elements from the old array to the new one, and then replaces the old array with the new one.