Мы можем использовать mutate_at
из dplyr
library(dplyr)
df %>%
mutate_at(vars(c("x1", "x2")), funs(replace(., y == 0, NA)))
# y x1 x2 x3
# 1 NA 1 9
#2 0 NA NA 5
#3 1 4 4 2
#4 1 7 7 4
#5 0 NA NA 7
#6 0 NA NA 2
#7 1 2 NA 5
#8 0 NA NA 8
#9 1 3 3 2
#10 0 NA NA 2
Вот хорошее обновление 2013 года с помощью [1 111] FastMember от NuGet:
IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data)) {
table.Load(reader);
}
Это использует метапрограммирование FastMember API для максимальной производительности. Если Вы хотите ограничить его конкретными участниками (или осуществлять порядок), то можно сделать это также:
IEnumerable<SomeType> data = ...
DataTable table = new DataTable();
using(var reader = ObjectReader.Create(data, "Id", "Name", "Description")) {
table.Load(reader);
}
Редактор Скидка / претендент: FastMember является проектом Marc Gravell. Его золотые и настоящие мухи!
<час> Да, это - в значительной степени полная противоположность [1 112] этот один; отражение было бы достаточно - или если Вам нужно более быстрый, HyperDescriptor
в 2,0, или возможно Expression
в 3,5. На самом деле, HyperDescriptor
должно быть более, чем соответствующим.
, Например:
// remove "this" if not on C# 3.0 / .NET 3.5
public static DataTable ToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection props =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
for(int i = 0 ; i < props.Count ; i++)
{
PropertyDescriptor prop = props[i];
table.Columns.Add(prop.Name, prop.PropertyType);
}
object[] values = new object[props.Count];
foreach (T item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = props[i].GetValue(item);
}
table.Rows.Add(values);
}
return table;
}
Теперь с одной строкой можно сделать это многими много раз быстрее, чем отражение (путем включения HyperDescriptor
для типа объекта T
).
запрос производительности ре редактирования; вот тестовая буровая установка с результатами:
Vanilla 27179
Hyper 6997
я подозреваю, что узкое место сместилось от членского доступа до [1 110] производительность... Я сомневаюсь, что Вы улучшитесь очень относительно этого...
код:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
public class MyData
{
public int A { get; set; }
public string B { get; set; }
public DateTime C { get; set; }
public decimal D { get; set; }
public string E { get; set; }
public int F { get; set; }
}
static class Program
{
static void RunTest(List<MyData> data, string caption)
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.WaitForFullGCComplete();
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < 500; i++)
{
data.ToDataTable();
}
watch.Stop();
Console.WriteLine(caption + "\t" + watch.ElapsedMilliseconds);
}
static void Main()
{
List<MyData> foos = new List<MyData>();
for (int i = 0 ; i < 5000 ; i++ ){
foos.Add(new MyData
{ // just gibberish...
A = i,
B = i.ToString(),
C = DateTime.Now.AddSeconds(i),
D = i,
E = "hello",
F = i * 2
});
}
RunTest(foos, "Vanilla");
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(
typeof(MyData));
RunTest(foos, "Hyper");
Console.ReadLine(); // return to exit
}
}
Чтобы преобразовать общий список в таблицу данных, вы можете использовать DataTableGenerator
Эта библиотека позволяет преобразовывать ваш список в таблицу данных с многофункциональностью, например
Ответ 2019 года при использовании.NET Core - использует библиотека Nuget ToDataTable . Преимущества:
Правовая оговорка - я - автор производительности ToDataTable
- я охватываю приблизительно Сравнительный тест .NET тесты и включал их в ToDataTable repo. Результаты были следующие:
Создание 100 000 Таблиц данных строки:
MacOS Windows
Reflection 818.5 ms 818.3 ms
FastMember from 1105.5 ms 976.4 ms
Mark's answer
Improved FastMember 524.6 ms 456.4 ms
ToDataTable 449.0 ms 376.5 ms
метод FastMember, предложенный в , ответ Marc , казалось, работал хуже, чем ответ Mary's , который использовал отражение, но я прокрутил другой метод использование FastMember TypeAccessor
, и это работало намного лучше. Тем не менее, пакет ToDataTable превзошел партию по характеристикам.
try this
public static DataTable ListToDataTable<T>(IList<T> lst)
{
currentDT = CreateTable<T>();
Type entType = typeof(T);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entType);
foreach (T item in lst)
{
DataRow row = currentDT.NewRow();
foreach (PropertyDescriptor prop in properties)
{
if (prop.PropertyType == typeof(Nullable<decimal>) || prop.PropertyType == typeof(Nullable<int>) || prop.PropertyType == typeof(Nullable<Int64>))
{
if (prop.GetValue(item) == null)
row[prop.Name] = 0;
else
row[prop.Name] = prop.GetValue(item);
}
else
row[prop.Name] = prop.GetValue(item);
}
currentDT.Rows.Add(row);
}
return currentDT;
}
public static DataTable CreateTable<T>()
{
Type entType = typeof(T);
DataTable tbl = new DataTable(DTName);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entType);
foreach (PropertyDescriptor prop in properties)
{
if (prop.PropertyType == typeof(Nullable<decimal>))
tbl.Columns.Add(prop.Name, typeof(decimal));
else if (prop.PropertyType == typeof(Nullable<int>))
tbl.Columns.Add(prop.Name, typeof(int));
else if (prop.PropertyType == typeof(Nullable<Int64>))
tbl.Columns.Add(prop.Name, typeof(Int64));
else
tbl.Columns.Add(prop.Name, prop.PropertyType);
}
return tbl;
}
Я сам написал небольшую библиотеку для выполнения этой задачи. Он использует отражение только в первый раз, когда тип объекта должен быть преобразован в таблицу данных. Он излучает метод, который сделает всю работу по преобразованию типа объекта.
Это невероятно быстро. Вы можете найти это здесь: ModelShredder в GoogleCode