เพิ่มรายการใหม่ในอาร์เรย์ที่มีอยู่ใน c # .net


134

จะเพิ่มรายการใหม่ในอาร์เรย์สตริงที่มีอยู่ใน C # .net ได้อย่างไร?

ฉันต้องการเก็บรักษาข้อมูลที่มีอยู่

คำตอบ:


121

ฉันจะใช้รายการถ้าคุณต้องการอาร์เรย์ขนาดไดนามิก:

List<string> ls = new List<string>();
ls.Add("Hello");

27
และถ้าจำเป็นให้ทำ ls ToArray () ตอนท้าย
Narayana

2
การใช้ช่างอื่นกว่าที่ถามในคำถามไม่ใช่คำตอบ
user11909

@ user2190035: ไม่แน่ใจว่าคุณได้แนวคิดนั้นมาจากไหนและ 111 คนที่โหวตเพิ่มจะไม่เห็นด้วยกับคุณ หากคุณรู้วิธีที่ดีกว่าในการขยายอาร์เรย์ให้โพสต์ไว้ ฉันสงสัยว่าการจัดสรรใหม่และสำเนาด้วยตนเองของคุณจะดีกว่าการใช้รายการ บางครั้งคำตอบคือ "อย่าทำอย่างนั้น"
Ed S.

@ EdS คำถามคือวิธีการเพิ่มรายการลงในอาร์เรย์สตริงที่มีอยู่แต่คำตอบนี้ไม่มีอาร์เรย์เลยมันจะสร้างรายการใหม่ขึ้นมาแทน ในแอปพลิเคชันของฉันฉันไม่สามารถเปลี่ยนประเภทเป็นรายการ <> ได้ดังนั้นฉันจึงต้องปรับขนาดอาร์เรย์ (กำลังทำสำเนา ... ) คำตอบของ Ali Ersözช่วยฉัน
user11909

@ user2190035: IEnumerable <T>. ToArray () ฉันเขียน C # ทุกวันและฉันไม่เคยต้องปรับขนาดอาร์เรย์แบบนั้น
Ed S.

100

นั่นอาจเป็นทางออก

Array.Resize(ref array, newsize);
array[newsize - 1] = "newvalue"

แต่สำหรับอาร์เรย์ขนาดไดนามิกฉันต้องการรายการด้วย


@ คอนราดนั่นจะรักษาข้อมูลในอาร์เรย์อย่างแน่นอน
Ali Ersöz

1
ไม่เหมาะสำหรับการเรียกใช้มากกว่าสองสามครั้ง เนื่องจากฟังก์ชัน 'ปรับขนาด' มีประสิทธิภาพสูง ข้อผิดพลาดหนึ่งหรือสองครั้งนี้เป็นสิ่งที่ดีมาก
โฆษณา

53

ใช้ LINQ:

arr = (arr ?? Enumerable.Empty<string>()).Concat(new[] { newitem }).ToArray();

ฉันชอบใช้สิ่งนี้เพราะมันเป็นหนึ่งซับและสะดวกมากในการฝังในคำสั่งสวิตช์คำสั่ง if แบบง่ายหรือส่งผ่านเป็นอาร์กิวเมนต์

แก้ไข:

บางคนไม่ชอบnew[] { newitem }เพราะมันสร้างอาร์เรย์ชั่วคราวขนาดเล็กรายการเดียว นี่คือเวอร์ชันที่ใช้Enumerable.Repeatซึ่งไม่จำเป็นต้องสร้างวัตถุใด ๆ (อย่างน้อยก็ไม่ใช่บนพื้นผิว - ตัวทำซ้ำ. NET อาจสร้างวัตถุเครื่องสถานะจำนวนมากใต้ตาราง)

arr = (arr ?? Enumerable.Empty<string>()).Concat(Enumerable.Repeat(newitem,1)).ToArray();

และถ้าคุณแน่ใจว่าอาร์เรย์ไม่เคยnullขึ้นต้นด้วยคุณสามารถทำให้อาร์เรย์ง่ายขึ้นเพื่อ:

arr.Concat(Enumerable.Repeat(newitem,1)).ToArray();

โปรดสังเกตว่าหากคุณต้องการเพิ่มรายการในคอลเลกชันที่สั่งซื้อListอาจเป็นโครงสร้างข้อมูลที่คุณต้องการไม่ใช่อาร์เรย์ที่จะเริ่มต้นด้วย


1
สวยมาก +1. ฉันมีรหัสที่คล้ายกันเป็นวิธีการขยายทั่วไป ฉันได้ใส่รหัสไว้ในคำตอบนี้: stackoverflow.com/a/11035286/673545
dblood

สิ่งนี้มีประโยชน์มากที่พบในขณะที่ค้นหา "วิธีต่อท้ายอาร์เรย์ในโค้ดบรรทัดเดียวใน c #" หวังว่าความคิดเห็นนี้จะเพียงพอที่จะพบอีกครั้งในครั้งต่อไป
gary

28

คำถามเก่ามาก แต่ยังต้องการเพิ่มสิ่งนี้

หากคุณกำลังมองหาซับเดียวคุณสามารถใช้รหัสด้านล่างนี้ มันรวมตัวสร้างรายการที่ยอมรับการแจงนับและไวยากรณ์ตัวเริ่มต้น "ใหม่" (ตั้งแต่ยกคำถาม)

myArray = new List<string>(myArray) { "add this" }.ToArray();

27

อาร์เรย์ใน C # จะไม่เปลี่ยนรูปเช่น,string[] int[]นั่นหมายความว่าคุณไม่สามารถปรับขนาดได้ คุณต้องสร้างอาร์เรย์ใหม่

นี่คือรหัสสำหรับArray.Resize :

public static void Resize<T>(ref T[] array, int newSize)
{
    if (newSize < 0)
    {
        throw new ArgumentOutOfRangeException("newSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
    }
    T[] sourceArray = array;
    if (sourceArray == null)
    {
        array = new T[newSize];
    }
    else if (sourceArray.Length != newSize)
    {
        T[] destinationArray = new T[newSize];
        Copy(sourceArray, 0, destinationArray, 0, (sourceArray.Length > newSize) ? newSize : sourceArray.Length);
        array = destinationArray;
    }
}

ดังที่คุณเห็นว่าสร้างอาร์เรย์ใหม่ที่มีขนาดใหม่คัดลอกเนื้อหาของอาร์เรย์ต้นทางและตั้งค่าการอ้างอิงไปยังอาร์เรย์ใหม่ คำแนะนำนี้คือคีย์เวิร์ดอ้างอิงสำหรับพารามิเตอร์แรก

มีรายการที่สามารถจัดสรรสล็อตใหม่สำหรับรายการใหม่แบบไดนามิก นี้เป็นเช่น<T> List เหล่านี้ประกอบด้วยอาร์เรย์ที่ไม่เปลี่ยนรูปและปรับขนาดได้เมื่อจำเป็น (รายการ <T> ไม่ใช่การใช้รายการที่เชื่อมโยง!) ArrayListเป็นสิ่งเดียวกันที่ไม่มี Generics (พร้อมObject array)

LinkedList <T>เป็นการใช้งานรายการที่เชื่อมโยงจริง น่าเสียดายที่คุณสามารถเพิ่มเพียงองค์ประกอบ LinkListNode <T> ในรายการดังนั้นคุณต้องรวมองค์ประกอบรายการของคุณเองลงในประเภทโหนดนี้ ฉันคิดว่าการใช้งานมันผิดปกติ


ฉันคิดว่าคุณหมายถึง Array.Copy
user123456

2
ตอบเฉพาะที่ให้ข้อมูลบางส่วนว่าเหตุใดจึงเป็นไปไม่ได้และไม่เพียงแนะนำให้ใช้รายการ ...
Gilad Green

ฉันเชื่อว่าAray.Resizeสามารถปรับขนาดอาร์เรย์ได้โดยไม่สูญเสียเนื้อหา docs.microsoft.com/en-us/dotnet/api/…
AbdelAziz AbdelLatef


7

คุณสามารถขยายคำตอบโดย @Stephen Chung ได้โดยใช้ตรรกะตาม LINQ ของเขาเพื่อสร้างวิธีการขยายโดยใช้ประเภททั่วไป

public static class CollectionHelper
{
    public static IEnumerable<T> Add<T>(this IEnumerable<T> sequence, T item)
    {
        return (sequence ?? Enumerable.Empty<T>()).Concat(new[] { item });
    }

    public static T[] AddRangeToArray<T>(this T[] sequence, T[] items)
    {
        return (sequence ?? Enumerable.Empty<T>()).Concat(items).ToArray();
    }

    public static T[] AddToArray<T>(this T[] sequence, T item)
    {
        return Add(sequence, item).ToArray();
    }

}

จากนั้นคุณสามารถเรียกมันได้โดยตรงบนอาร์เรย์เช่นนี้

    public void AddToArray(string[] options)
    {
        // Add one item
        options = options.AddToArray("New Item");

        // Add a 
        options = options.AddRangeToArray(new string[] { "one", "two", "three" });

        // Do stuff...
    }

เป็นที่ยอมรับว่าเมธอด AddRangeToArray () ดูเหมือนจะใช้งานมากเกินไปเนื่องจากคุณมีฟังก์ชันการทำงานเดียวกันกับ Concat () แต่ด้วยวิธีนี้โค้ดสุดท้ายสามารถ "ทำงาน" กับอาร์เรย์ได้โดยตรงเมื่อเทียบกับสิ่งนี้:

options = options.Concat(new string[] { "one", "two", "three" }).ToArray();

ขอบคุณสิ่งนี้มีประโยชน์มากฉันได้เพิ่มตัวเลือกในการลบรายการ (ฉันหวังว่าสิ่งนี้จะใช้ได้กับคุณ)
Tal Segal

@TalSegal คุณยินดีต้อนรับความสุขของฉัน ใช้รหัสตามที่เห็นสมควร!
dblood

6

จะดีกว่าที่จะทำให้ Array ไม่เปลี่ยนรูปและขนาดคงที่

คุณสามารถจำลองAddโดยExtension MethodและIEnumerable.Concat()

public static class ArrayExtensions
    {
        public static string[] Add(this string[] array, string item)
        {
            return array.Concat(new[] {item}).ToArray();
        }
    }

5

หากคุณใช้งานอาร์เรย์เป็นจำนวนมากและไม่ได้แสดงรายการด้วยเหตุผลบางประการวิธีการทั่วไปที่พิมพ์โดยทั่วไปนี้Addอาจช่วยได้

    public static T[] Add<T>(T[] array, T item)
    {
        T[] returnarray = new T[array.Length + 1];
        for (int i = 0; i < array.Length; i++)
        {
            returnarray[i] = array[i];
        }
        returnarray[array.Length] = item;
        return returnarray;
    }

4

คำตอบที่เสนอทั้งหมดทำเช่นเดียวกับสิ่งที่พวกเขาบอกว่าต้องการหลีกเลี่ยงสร้างอาร์เรย์ใหม่และเพิ่มรายการใหม่ในนั้นโดยที่สูญเสียค่าโสหุ้ยมากขึ้นเท่านั้น LINQ ไม่ใช่เวทย์มนตร์รายการของ T คืออาร์เรย์ที่มีพื้นที่บัฟเฟอร์ที่มีพื้นที่พิเศษเพื่อหลีกเลี่ยงการปรับขนาดอาร์เรย์ภายในเมื่อมีการเพิ่มรายการ

นามธรรมทั้งหมดต้องแก้ปัญหาเดียวกันสร้างอาร์เรย์โดยไม่มีช่องว่างที่เก็บค่าทั้งหมดแล้วส่งคืน

หากคุณต้องการความยืดหยุ่นสามารถสร้างรายการที่มีขนาดใหญ่พอที่คุณสามารถใช้เพื่อส่งผ่านได้ให้ทำเช่นนั้น อื่นใช้อาร์เรย์และแบ่งปันวัตถุที่ปลอดภัยของเธรดนั้น นอกจากนี้ Span ใหม่ยังช่วยแชร์ข้อมูลโดยไม่ต้องคัดลอกรายการรอบ ๆ

เพื่อตอบคำถาม:

Array.Resize(ref myArray, myArray.Length + 1);
data[myArray.Length - 1] = Value;

4

ดังนั้นหากคุณมีอาร์เรย์อยู่แล้วการแก้ไขด่วนของฉันจะเป็น

var tempList = originalArray.ToList();
tempList.Add(newitem);

ตอนนี้เพียงแค่แทนที่อาร์เรย์เดิมด้วยอาร์เรย์ใหม่

originalArray = tempList.ToArray();

แก้ไขวิธีแก้ปัญหาของฉัน
praguan

3

Append<TSource>มีการเพิ่มวิธีการใหม่ในIEnumerable<TSource>ตั้งแต่. NET Framework 4.7.1 และ. NET Core 1.0

นี่คือวิธีการใช้งาน:

var numbers = new [] { "one", "two", "three" };
numbers = numbers.Append("four").ToArray();
Console.WriteLine(string.Join(", ", numbers)); // one, two, three, four

โปรดทราบว่าหากคุณต้องการเพิ่มองค์ประกอบที่จุดเริ่มต้นของอาร์เรย์คุณสามารถใช้Prepend<TSource>วิธีการใหม่แทนได้


2

การใช้รายการจะเป็นตัวเลือกที่ดีที่สุดสำหรับการจัดการหน่วยความจำ


2

แล้วการใช้วิธีการขยายล่ะ? ตัวอย่างเช่น:

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> source, TSource item)
{
    return source.Union(new TSource[] { item });
}

ตัวอย่างเช่น:

string[] sourceArray = new []
{
    "foo",
    "bar"
}
string additionalItem = "foobar";
string result = sourceArray.Union(additionalItem);

สังเกตว่านี่เป็นการเลียนแบบลักษณะการทำงานของส่วนขยาย Uniion ของ Linq (ใช้เพื่อรวมอาร์เรย์สองอาร์เรย์เข้าด้วยกันเป็นอาร์เรย์ใหม่) และต้องการให้ไลบรารี Linq ทำงาน


1

ฉันเห็นด้วยกับเอ็ด C # ไม่ทำให้เรื่องนี้ง่ายเหมือนที่ VB ทำกับ ReDim Preserve หากไม่มีคอลเล็กชันคุณจะต้องคัดลอกอาร์เรย์ให้ใหญ่ขึ้น


2
ขอบคุณพระเจ้า! ReDim ช้าอย่างเหลือเชื่อเมื่อถูกทำร้าย =)
Ed S.

ReDim Preserveเพียงแค่คัดลอกอาร์เรย์ลงในเบียร์ ไม่มีการปรับขนาดอาร์เรย์ที่น่าอัศจรรย์
Olivier Jacot-Descombes


0
private static string[] GetMergedArray(string[] originalArray, string[] newArray)
    {
        int startIndexForNewArray = originalArray.Length;
        Array.Resize<string>(ref originalArray, originalArray.Length + newArray.Length);
        newArray.CopyTo(originalArray, startIndexForNewArray);
        return originalArray;
    }


0

น่าเสียดายที่การใช้รายการไม่สามารถใช้ได้ในทุกสถานการณ์ รายการและอาร์เรย์แตกต่างกันจริง ๆ และไม่สามารถใช้แทนกันได้ 100% มันจะขึ้นอยู่กับสถานการณ์ว่านี่จะเป็นการแก้ปัญหาที่ยอมรับได้หรือไม่


0

เนื่องจากคำถามนี้ไม่พอใจกับคำตอบที่ให้มาฉันจึงขอเพิ่มคำตอบนี้ :)

public class CustomArrayList<T> 
 {  
   private T[] arr;  private int count;  

public int Count  
  {   
    get   
      {    
        return this.count;   
      }  
   }  
 private const int INITIAL_CAPACITY = 4;  

 public CustomArrayList(int capacity = INITIAL_CAPACITY) 
 {  
    this.arr = new T[capacity];   this.count = 0; 
  } 

 public void Add(T item) 
  {  
    GrowIfArrIsFull();  
   this.arr[this.count] = item;  this.count++; 
  }  

public void Insert(int index, T item) 
{  
 if (index > this.count || index < 0)  
    {   
      throw new IndexOutOfRangeException(    "Invalid index: " + index);  
     }  
     GrowIfArrIsFull();  
     Array.Copy(this.arr, index,   this.arr, index + 1, this.count - index);          
    this.arr[index] = item;  this.count++; }  

    private void GrowIfArrIsFull() 
    {  
    if (this.count + 1 > this.arr.Length)  
    {   
      T[] extendedArr = new T[this.arr.Length * 2];  
      Array.Copy(this.arr, extendedArr, this.count);  
      this.arr = extendedArr;  
    } 
  }
 }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.