Отредактировано для включения взвешенных сумм.
Это может быть очень приятный трюк, но наиболее простой (и обслуживаемый) способ - это, вероятно, простая for
-цикличная реализация.
M1 <- matrix(1:16, nr=4)
M1
# [,1] [,2] [,3] [,4]
# [1,] 1 5 9 13
# [2,] 2 6 10 14
# [3,] 3 7 11 15
# [4,] 4 8 12 16
Код:
get_neighbors <- function(M, radius = 1) {
M2 <- M
M2[] <- 0
nr <- nrow(M)
nc <- ncol(M)
eg <- expand.grid((-radius):radius, (-radius):radius)
eg$wt <- exp(-sqrt(abs(eg[,1]) + abs(eg[,2])))
for (R in seq_len(nr)) {
for (C in seq_len(nc)) {
ind <- cbind(R + eg[,1], C + eg[,2], eg[,3])
ind <- ind[ 0 < ind[,1] & ind[,1] <= nr &
0 < ind[,2] & ind[,2] <= nc,, drop = FALSE ]
M2[R,C] <- sum(M[ind[,1:2, drop=FALSE]] * ind[,3])
}
}
M2
}
get_neighbors(M1, 1)
# [,1] [,2] [,3] [,4]
# [1,] 5.033856 13.80347 24.16296 23.89239
# [2,] 8.596195 20.66391 34.43985 32.84175
# [3,] 11.186067 24.10789 37.88383 35.43163
# [4,] 9.748491 19.86486 30.22435 28.60703
То же самое, с радиусом 2:
get_neighbors(M1, 2)
# [,1] [,2] [,3] [,4]
# [1,] 12.44761 25.64963 31.73247 32.70974
# [2,] 18.57765 35.96237 43.33862 43.51911
# [3,] 20.09836 37.80643 45.18268 45.03982
# [4,] 17.51314 31.88500 37.96784 37.77527
И простой тест, если используется радиус 0, тогда M1 и M2 должны быть идентичны (они есть).
Примечание: это обычно выполняет очень хорошо в базе R, без всякого причудливого использования apply
или его кузенов. Поскольку это действительно простая эвристика, ее можно легко реализовать с помощью Rcpp, чтобы она была значительно быстрее.
В зависимости от Вашего варианта использования, если пустой указатель можно рассмотреть как совпадение с неопределенным, можно превратить ExpandoObject в DynamicJsonObject.
dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject());
x.a = 1;
x.b = 2.50;
Console.WriteLine("a is " + (x.a ?? "undefined"));
Console.WriteLine("b is " + (x.b ?? "undefined"));
Console.WriteLine("c is " + (x.c ?? "undefined"));
Вывод:
a is 1
b is 2.5
c is undefined
Эй, ребята, прекратите использовать Reflection для всего, что требует большого количества циклов процессора.
Вот решение:
public class DynamicDictionary : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public int Count
{
get
{
return dictionary.Count;
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name;
if (!dictionary.TryGetValue(binder.Name, out result))
result = "undefined";
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
}
Согласно MSDN объявление показывает, что он реализует IDictionary:
public sealed class ExpandoObject : IDynamicMetaObjectProvider,
IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>,
IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged
Вы можете использовать это, чтобы увидеть, есть ли член определен:
var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
// expandoObject.SomeMember exists.
}
Почему вы не хотите использовать Reflection для получения набора свойств типа? Вот так
dynamic v = new Foo();
Type t = v.GetType();
System.Reflection.PropertyInfo[] pInfo = t.GetProperties();
if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }). GetValue(v, null) != null))
{
//PropName initialized
}
Недавно я ответил на очень похожий вопрос: Как мне размышлять над членами динамический объект?
Вкратце, ExpandoObject - не единственный динамический объект, который вы можете получить. Отражение будет работать для статических типов (типов, которые не реализуют IDynamicMetaObjectProvider). Для типов, реализующих этот интерфейс, отражение в основном бесполезно. Для ExpandoObject вы можете просто проверить, определено ли свойство как ключ в базовом словаре. Для других реализаций это может быть сложно, и иногда единственный способ - работать с исключениями. Для получения подробной информации перейдите по ссылке выше.