Работает ли наследование только в одном направлении? [Дубликат]

Вы также можете попробовать idxmax:

In [5]: df = pandas.DataFrame(np.random.randn(10,3),columns=['A','B','C'])

In [6]: df
Out[6]: 
          A         B         C
0  2.001289  0.482561  1.579985
1 -0.991646 -0.387835  1.320236
2  0.143826 -1.096889  1.486508
3 -0.193056 -0.499020  1.536540
4 -2.083647 -3.074591  0.175772
5 -0.186138 -1.949731  0.287432
6 -0.480790 -1.771560 -0.930234
7  0.227383 -0.278253  2.102004
8 -0.002592  1.434192 -1.624915
9  0.404911 -2.167599 -0.452900

In [7]: df.idxmax()
Out[7]: 
A    0
B    8
C    7

, например

In [8]: df.loc[df['A'].idxmax()]
Out[8]: 
A    2.001289
B    0.482561
C    1.579985
46
задан AndiDog 9 January 2010 в 16:59
поделиться

4 ответа

Хорошо, что это не будет поддерживаться на C # 4. Существует фундаментальная проблема:

List<Giraffe> giraffes = new List<Giraffe>();
giraffes.Add(new Giraffe());
List<Animal> animals = giraffes;
animals.Add(new Lion()); // Aargh!

Хранить жирафов в безопасности: просто скажите «нет» небезопасной дисперсии.

Массив версия работает, потому что массивы do поддерживают отклонение ссылочного типа с проверкой времени выполнения. Пункт дженериков состоит в том, чтобы обеспечить безопасность типа compile-time .

В C # 4 будет поддерживаться универсальная дисперсия safe , но только для интерфейсов и делегатов. Таким образом, вы сможете:

Func<string> stringFactory = () => "always return this string";
Func<object> objectFactory = stringFactory; // Safe, allowed in C# 4

Func<out T> covariant в T, потому что T используется только в выходной позиции. Сравните это с Action<in T>, который контравариантен в T, потому что T используется только там, где находится входное положение, делая это безопасным:

Action<object> objectAction = x => Console.WriteLine(x.GetHashCode());
Action<string> stringAction = objectAction; // Safe, allowed in C# 4

IEnumerable<out T> также является ковариантным, делая это исправить в C # 4, как указано другими:

IEnumerable<Animal> animals = new List<Giraffe>();
// Can't add a Lion to animals, as `IEnumerable<out T>` is a read-only interface.

Что касается работы с этим в вашей ситуации на C # 2, вам нужно поддерживать список one или Вы были бы счастливы создать новый список? Если это приемлемо, List<T>.ConvertAll является вашим другом.

98
ответ дан Jon Skeet 20 August 2018 в 21:32
поделиться
  • 1
    +1, чтобы добавить к ответу Джона (не то, что ему нужна помощь), следуя примеру Func<string> - Func<object> и факту, что T контравариантно в Action. Следующий Action<object> = Action<string> не будет работать в C # 4. – Stan R. 9 January 2010 в 17:17
  • 2
    Спасибо за то, что он указал на проблему безопасности типа. Это действительно полезно. – AndiDog 9 January 2010 в 17:25
  • 3
    Что случилось с animals.Add(new Lion()); // Aargh!? Если вы можете использовать Lion и использовать его как Animal, и если вы используете все элементы в animals как Animal s, то в чем проблема? – Jeff 12 April 2017 в 20:04
  • 4
    @Jeff: Поскольку animals фактически относится к List<Giraffe>. Таким образом, вы получите ссылку Lion в List<Giraffe>, что плохо ... – Jon Skeet 12 April 2017 в 20:32
  • 5
  • 6

Ковариация / контравариантность не могут поддерживаться в изменчивых коллекциях, о которых упоминали другие, потому что невозможно гарантировать безопасность типов во время компиляции; однако, можно сделать быстрое одностороннее преобразование в C # 3.5, если это то, что вы ищете:

List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = giraffes.Cast<Animal>().ToList();

Конечно, это не одно и то же, это не ковариантность - вы фактически создаете еще один список, но это «обходной путь», так сказать.

В .NET 2.0 вы можете использовать ковариацию массива для упрощения кода:

List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = new List<Animal>(giraffes.ToArray());

Но имейте в виду, что вы на самом деле создаете две новые коллекции здесь.

4
ответ дан Aaronaught 20 August 2018 в 21:32
поделиться
  • 1
    Я думаю, что это довольно хорошие обходные пути для моего простого приложения. По крайней мере, они хороши для читаемости - не для производительности. – AndiDog 9 January 2010 в 17:26
  • 2
    @JohnAskew: я не уверен, что вы здесь делаете - на IList<T> нет метода Cast, это метод расширения Enumerable<T>.Cast<T2>, который принимает IEnumerable<T> и явно передает каждый элемент в T2, а затем возвращает его (как IEnumerable<T2>, а не IList<T2>). Это не имеет никакого отношения к IList<T> вообще, за исключением того факта, что IList<T> наследуется от IEnumerable<T> и, таким образом, поддерживает методы расширения Enumerable<T>. Ковариантности там нет. – Aaronaught 22 July 2014 в 15:17
  • 3
    К сожалению ... Я щелкнул delete вместо редактирования: -S – John Askew 23 July 2014 в 15:14
  • 4
    Я не видел ссылку на C # 3.5 и имел в виду C # 4.0, где IEnumerable & lt; T & gt; интерфейс был обновлен, чтобы быть IEnumerable & lt; out T & gt; и Cast & lt; T & gt; метод изменен для использования ковариации: IEnumerable & lt; TResult & gt; typedSource = source как IEnumerable & lt; TResult & gt; а не итерации с явным литьем. – John Askew 23 July 2014 в 15:22

В терминах List<T>, боюсь, вам не повезло. Тем не менее, .NET 4.0 / C # 4.0 добавляет поддержку ковариантных / контравариантных интерфейсов. В частности, IEnumerable<T> теперь определяется как IEnumerable<out T> , что означает, что параметр типа теперь ковариант .

Это означает, что вы можете что-то сделать например, в C # 4.0 ...

// implicit casting
IEnumerable<Animal> animalsList = new List<Giraffe>();

// explicit casting
IEnumerable<Animal> animalsList2 = (IEnumerable<Animal>) new List<Giraffe>();

Примечание. Типы массивов также были ковариантными (по крайней мере с .NET 1.1).

Я считаю, что стыдно, что поддержка дисперсии не был добавлен для IList<T> и других подобных общих интерфейсов (или общих классов), но, по крайней мере, у нас есть что-то.

6
ответ дан EMP 20 August 2018 в 21:32
поделиться
  • 1
    Вы не можете сделать IList & lt; T & gt; covariant безопасно с аннотациями вариации на стороне объявления. – Eric Lippert 9 January 2010 в 20:34

Он будет работать в C # 4 для IEnumerable<T>, поэтому вы можете сделать:

IEnumerable<Animal> animals = new List<Giraffe>();

Однако List<T> не является ковариационной проекцией, поэтому вы не можете назначать списки, как вы это делали выше так как вы могли бы сделать это:

List<Animal> animals = new List<Giraffe>();
animals.Add(new Monkey());

Это явно недействительно.

12
ответ дан Lee 20 August 2018 в 21:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: