ฉันมีอาร์เรย์ของวัตถุ Foo ฉันจะลบองค์ประกอบที่สองของอาร์เรย์ได้อย่างไร
ฉันต้องการสิ่งที่คล้ายกับRemoveAt()
แต่สำหรับอาร์เรย์ปกติ
ฉันมีอาร์เรย์ของวัตถุ Foo ฉันจะลบองค์ประกอบที่สองของอาร์เรย์ได้อย่างไร
ฉันต้องการสิ่งที่คล้ายกับRemoveAt()
แต่สำหรับอาร์เรย์ปกติ
คำตอบ:
หากคุณไม่ต้องการใช้รายการ:
var foos = new List<Foo>(array);
foos.RemoveAt(index);
return foos.ToArray();
คุณสามารถลองวิธีการขยายนี้ที่ฉันยังไม่ได้ทดสอบ:
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;
}
และใช้มันเช่น:
Foo[] bar = GetFoos();
bar = bar.RemoveAt(2);
ธรรมชาติของอาร์เรย์คือความยาวไม่เปลี่ยนรูป คุณไม่สามารถเพิ่มหรือลบรายการอาร์เรย์ใด ๆ
คุณจะต้องสร้างอาร์เรย์ใหม่ที่สั้นกว่าหนึ่งองค์ประกอบและคัดลอกรายการเก่าไปยังอาร์เรย์ใหม่โดยไม่รวมองค์ประกอบที่คุณต้องการลบ
ดังนั้นจึงน่าจะดีกว่าที่จะใช้ List แทนอาร์เรย์
List<mydatatype> array = new List<mydatatype>(arrayofmydatatype)
var myList = myArray.ToList();
ใช้Enumerable.ToList()
วิธีการจากSystem.Linq
เนมสเปซ
ฉันใช้วิธีนี้เพื่อลบองค์ประกอบออกจากอาร์เรย์วัตถุ ในสถานการณ์ของฉันอาร์เรย์ของฉันมีความยาวน้อย ดังนั้นหากคุณมีอาร์เรย์ขนาดใหญ่คุณอาจต้องการโซลูชันอื่น
private int[] RemoveIndices(int[] IndicesArray, int RemoveAt)
{
int[] newIndicesArray = new int[IndicesArray.Length - 1];
int i = 0;
int j = 0;
while (i < IndicesArray.Length)
{
if (i != RemoveAt)
{
newIndicesArray[j] = IndicesArray[i];
j++;
}
i++;
}
return newIndicesArray;
}
LINQ โซลูชันหนึ่งบรรทัด:
myArray = myArray.Where((source, index) => index != 1).ToArray();
1
ในตัวอย่างที่เป็นดัชนีขององค์ประกอบในการลบ - ในตัวอย่างนี้ต่อคำถามเดิมองค์ประกอบที่ 2 (มี1
เป็นองค์ประกอบที่สองใน C # zero-based การจัดทำดัชนีอาร์เรย์)
ตัวอย่างที่สมบูรณ์ยิ่งขึ้น:
string[] myArray = { "a", "b", "c", "d", "e" };
int indexToRemove = 1;
myArray = myArray.Where((source, index) => index != indexToRemove).ToArray();
หลังจากใช้ข้อมูลโค้ดที่ค่าของจะmyArray
{ "a", "c", "d", "e" }
นี่เป็นวิธีการลบองค์ประกอบอาร์เรย์ ณ . Net 3.5 โดยไม่ต้องคัดลอกไปยังอาร์เรย์อื่นโดยใช้อินสแตนซ์อาร์เรย์เดียวกันกับArray.Resize<T>
:
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);
}
ref
เมื่อคุณเรียกใช้Resize
เมธอด ความยาวของอินสแตนซ์อาร์เรย์ได้รับการแก้ไขและไม่เปลี่ยนรูป
นี่คือเวอร์ชันเก่าที่ฉันมีซึ่งใช้งานได้กับ. NET framework เวอร์ชัน 1.0 และไม่จำเป็นต้องใช้ประเภททั่วไป
public static Array RemoveAt(Array source, int index)
{
if (source == null)
throw new ArgumentNullException("source");
if (0 > index || index >= source.Length)
throw new ArgumentOutOfRangeException("index", index, "index is outside the bounds of source array");
Array dest = Array.CreateInstance(source.GetType().GetElementType(), source.Length - 1);
Array.Copy(source, 0, dest, 0, index);
Array.Copy(source, index + 1, dest, index, source.Length - index - 1);
return dest;
}
ใช้ในลักษณะนี้:
class Program
{
static void Main(string[] args)
{
string[] x = new string[20];
for (int i = 0; i < x.Length; i++)
x[i] = (i+1).ToString();
string[] y = (string[])MyArrayFunctions.RemoveAt(x, 3);
for (int i = 0; i < y.Length; i++)
Console.WriteLine(y[i]);
}
}
ไม่ใช่วิธีที่จะดำเนินต่อไปอย่างแน่นอน แต่ถ้าสถานการณ์ไม่สำคัญและคุณให้ความสำคัญกับเวลาของคุณคุณสามารถลองสิ่งนี้สำหรับประเภทที่เป็นโมฆะได้
Foos[index] = null
และตรวจสอบรายการว่างในตรรกะของคุณในภายหลัง ..
ตามปกติฉันไปงานปาร์ตี้สาย ...
ฉันต้องการเพิ่มตัวเลือกอื่นในรายการโซลูชันที่ดีที่มีอยู่แล้ว =)
ฉันเห็นว่านี่เป็นโอกาสที่ดีสำหรับส่วนขยาย
อ้างอิง:
http://msdn.microsoft.com/en-us/library/bb311042.aspx
ดังนั้นเราจึงกำหนดคลาสคงที่และในนั้นวิธีการของเรา
หลังจากนั้นเราสามารถใช้วิธีการเพิ่มเติมของเราโดยเต็มใจ =)
using System;
namespace FunctionTesting {
// The class doesn't matter, as long as it's static
public static class SomeRandomClassWhoseNameDoesntMatter {
// Here's the actual method that extends arrays
public static T[] RemoveAt<T>( this T[] oArray, int idx ) {
T[] nArray = new T[oArray.Length - 1];
for( int i = 0; i < nArray.Length; ++i ) {
nArray[i] = ( i < idx ) ? oArray[i] : oArray[i + 1];
}
return nArray;
}
}
// Sample usage...
class Program {
static void Main( string[] args ) {
string[] myStrArray = { "Zero", "One", "Two", "Three" };
Console.WriteLine( String.Join( " ", myStrArray ) );
myStrArray = myStrArray.RemoveAt( 2 );
Console.WriteLine( String.Join( " ", myStrArray ) );
/* Output
* "Zero One Two Three"
* "Zero One Three"
*/
int[] myIntArray = { 0, 1, 2, 3 };
Console.WriteLine( String.Join( " ", myIntArray ) );
myIntArray = myIntArray.RemoveAt( 2 );
Console.WriteLine( String.Join( " ", myIntArray ) );
/* Output
* "0 1 2 3"
* "0 1 3"
*/
}
}
}
ลองใช้รหัสด้านล่าง:
myArray = myArray.Where(s => (myArray.IndexOf(s) != indexValue)).ToArray();
หรือ
myArray = myArray.Where(s => (s != "not_this")).ToArray();
นี่คือวิธีที่ฉันทำ ...
public static ElementDefinitionImpl[] RemoveElementDefAt(
ElementDefinition[] oldList,
int removeIndex
)
{
ElementDefinitionImpl[] newElementDefList = new ElementDefinitionImpl[ oldList.Length - 1 ];
int offset = 0;
for ( int index = 0; index < oldList.Length; index++ )
{
ElementDefinitionImpl elementDef = oldList[ index ] as ElementDefinitionImpl;
if ( index == removeIndex )
{
// This is the one we want to remove, so we won't copy it. But
// every subsequent elementDef will by shifted down by one.
offset = -1;
}
else
{
newElementDefList[ index + offset ] = elementDef;
}
}
return newElementDefList;
}
ในอาร์เรย์ปกติคุณต้องสลับรายการอาร์เรย์ทั้งหมดที่อยู่เหนือ 2 จากนั้นปรับขนาดโดยใช้วิธีการปรับขนาด คุณอาจจะดีกว่าการใช้ ArrayList
private int[] removeFromArray(int[] array, int id)
{
int difference = 0, currentValue=0;
//get new Array length
for (int i=0; i<array.Length; i++)
{
if (array[i]==id)
{
difference += 1;
}
}
//create new array
int[] newArray = new int[array.Length-difference];
for (int i = 0; i < array.Length; i++ )
{
if (array[i] != id)
{
newArray[currentValue] = array[i];
currentValue += 1;
}
}
return newArray;
}
นี่คือชุดวิธีช่วยเหลือเล็ก ๆ น้อย ๆ ที่ฉันสร้างขึ้นจากคำตอบที่มีอยู่บางส่วน ใช้ทั้งส่วนขยายและวิธีการแบบคงที่พร้อมพารามิเตอร์อ้างอิงเพื่อความเหมาะสมสูงสุด:
public static class Arr
{
public static int IndexOf<TElement>(this TElement[] Source, TElement Element)
{
for (var i = 0; i < Source.Length; i++)
{
if (Source[i].Equals(Element))
return i;
}
return -1;
}
public static TElement[] Add<TElement>(ref TElement[] Source, params TElement[] Elements)
{
var OldLength = Source.Length;
Array.Resize(ref Source, OldLength + Elements.Length);
for (int j = 0, Count = Elements.Length; j < Count; j++)
Source[OldLength + j] = Elements[j];
return Source;
}
public static TElement[] New<TElement>(params TElement[] Elements)
{
return Elements ?? new TElement[0];
}
public static void Remove<TElement>(ref TElement[] Source, params TElement[] Elements)
{
foreach (var i in Elements)
RemoveAt(ref Source, Source.IndexOf(i));
}
public static void RemoveAt<TElement>(ref TElement[] Source, int Index)
{
var Result = new TElement[Source.Length - 1];
if (Index > 0)
Array.Copy(Source, 0, Result, 0, Index);
if (Index < Source.Length - 1)
Array.Copy(Source, Index + 1, Result, Index, Source.Length - Index - 1);
Source = Result;
}
}
ประสิทธิภาพที่ดีเป็นสิ่งที่ดี แต่มันอาจจะดีขึ้น Remove
อาศัยและอาร์เรย์ใหม่ถูกสร้างขึ้นสำหรับองค์ประกอบที่คุณต้องการที่จะลบโดยการเรียกแต่ละIndexOf
RemoveAt
IndexOf
เป็นวิธีการขยายเพียงวิธีเดียวเนื่องจากไม่จำเป็นต้องส่งคืนอาร์เรย์เดิม New
ยอมรับหลายองค์ประกอบบางประเภทเพื่อสร้างอาร์เรย์ใหม่ของประเภทดังกล่าว วิธีการอื่น ๆ ทั้งหมดต้องยอมรับอาร์เรย์ดั้งเดิมเป็นข้อมูลอ้างอิงดังนั้นจึงไม่จำเป็นต้องกำหนดผลลัพธ์ในภายหลังเนื่องจากเกิดขึ้นภายในแล้ว
ฉันจะกำหนดMerge
วิธีการรวมสองอาร์เรย์ อย่างไรก็ตามสามารถทำได้ด้วยAdd
วิธีการอยู่แล้วโดยส่งผ่านอาร์เรย์จริงกับหลายองค์ประกอบแต่ละรายการ ดังนั้นAdd
อาจใช้สองวิธีต่อไปนี้เพื่อรวมสองชุดขององค์ประกอบ:
Arr.Add<string>(ref myArray, "A", "B", "C");
หรือ
Arr.Add<string>(ref myArray, anotherArray);
ฉันรู้ว่าบทความนี้มีอายุสิบปีและอาจถึงแก่ความตาย แต่นี่คือสิ่งที่ฉันจะลองทำ:
ใช้ IEnumerable.Skip () วิธีการที่พบใน System.Linq มันจะข้ามองค์ประกอบที่เลือกจากอาร์เรย์และส่งคืนสำเนาของอาร์เรย์อีกชุดที่มีเฉพาะทุกอย่างยกเว้นวัตถุที่เลือก จากนั้นทำซ้ำทุกองค์ประกอบที่คุณต้องการลบและหลังจากนั้นให้บันทึกลงในตัวแปร
ตัวอย่างเช่นถ้าเรามีอาร์เรย์ชื่อ "ตัวอย่าง" (ประเภท int []) ที่มีตัวเลข 5 ตัว เราต้องการลบอันที่ 2 ออกจึงลอง "Sample.Skip (2);" ควรส่งคืนอาร์เรย์เดียวกันยกเว้นไม่มีหมายเลขที่ 2
ขั้นตอนแรก
คุณต้องแปลงอาร์เรย์เป็นรายการคุณสามารถเขียนวิธีการขยายได้เช่นนี้
// Convert An array of string to a list of string
public static List<string> ConnvertArrayToList(this string [] array) {
// DECLARE a list of string and add all element of the array into it
List<string> myList = new List<string>();
foreach( string s in array){
myList.Add(s);
}
return myList;
}
ขั้นตอนที่สอง
เขียนวิธีการขยายเพื่อแปลงกลับรายการเป็นอาร์เรย์
// convert a list of string to an array
public static string[] ConvertListToArray(this List<string> list) {
string[] array = new string[list.Capacity];
array = list.Select(i => i.ToString()).ToArray();
return array;
}
ขั้นตอนสุดท้าย
เขียนวิธีสุดท้ายของคุณ แต่อย่าลืมลบองค์ประกอบที่ดัชนีก่อนที่จะแปลงกลับเป็นอาร์เรย์เช่นการแสดงโค้ด
public static string[] removeAt(string[] array, int index) {
List<string> myList = array.ConnvertArrayToList();
myList.RemoveAt(index);
return myList.ConvertListToArray();
}
โค้ดตัวอย่างสามารถพบได้ในบล็อกของฉันติดตามต่อไป
.ToArray()
และตัวList<T>
สร้างซึ่งใช้ลำดับที่มีอยู่ ...
System.Collections.ObjectModel.Collection<Foo>
.