c#获取两个使用结构的列表之间的差异

时间:2016-12-08 22:12:00

标签: c#

这是我的第一篇文章。 我在c#中相当新,我正在尝试使用结构类型的列表。

package config.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import services.security.CustomUserDetailsService;
/**
 *
 * @author sergio
 */
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = CustomUserDetailsService.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher;

    @Bean
    public PasswordEncoder passwordEncoder() {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
         auth
            .authenticationEventPublisher(defaultAuthenticationEventPublisher)
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/signup").anonymous()
                .antMatchers("/admin/**").authenticated()
                .anyRequest().permitAll()
                .and()
                .formLogin().loginPage("/admin/login").permitAll()
                .usernameParameter("username").passwordParameter("password")
                .and()
                .logout()
                    .logoutRequestMatcher(new AntPathRequestMatcher("/admin/logout"))
                    .logoutSuccessUrl("/admin/login?logout")
                .and()
                .exceptionHandling().accessDeniedPage("/403")
                .and()
                .csrf();
    }

    @Bean
    public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
    }
}

到目前为止,我所做的一切都使用了已知的类型(例如字符串),但对于上面示例中的列表,我不能使用任何具有正结果的函数。

目前,我们的想法是获得使用该结构类型(List)的两个列表之间的差异。 BigList将始终拥有比Small列表更多的项目,并且想法是查找在BigList中不存在的SmalList中的所有项目,考虑到Field1。理想情况下,结果可能是相同类型的列表(列表)。

这可能吗? 我已经尝试了一些我在 stackoverflow 中找到的示例,但找不到很多使用结构列表的示例,而我尝试过的示例也无效。

一个符合字符串列表的例子:

public struct MyStruct
{
    public string Field1;
    public string Field2;
}

List<MyStruct> BigList = new List<MyStruct> { };
List<MyStruct> SmallList = new List<MyStruct> { }; 

可能是一个解决方案,但我需要查看一个字段(结构的Field1)而不仅仅是一个简单的字符串。

对于那些类型的列表使用.Sort或.Contains不能获得正面结果(专门查看结构的一个字段,例如List)。

有人能帮助我吗? 那太好了!

提前致谢。 的问候,

5 个答案:

答案 0 :(得分:2)

正如其他人所说,在你的例子中使用结构,特别是因为你是C#的新手,可能是一个错误,而不是一个真正的好主意。我建议你用类替换你的结构。

您遇到的问题是因为您使用的是您自己定义的类型,因此该比较无法正常工作,或者至少不会像您预期的那样发挥作用上班。

它不知道如何比较两个对象,并且在类的情况下,将验证它是否是相同的对象,并且在结构的情况下要么进行逐字节比较(如果struct不包含引用类型)或比较它包含的引用是否相同(如果struct包含引用类型)。

要使一切正常工作,您需要做的是覆盖班级中的Equals方法。请参阅此MSDN文章以开始此操作:https://msdn.microsoft.com/en-us/library/336aedhh(v=vs.100).aspx

或者,您可以为您的类型实现IEqualityComparer。如果您无法访问类实现,那么它特别有用。请查看此MSDN文章:https://msdn.microsoft.com/en-us/library/bb300779(v=vs.110).aspx

答案 1 :(得分:0)

有很多方法可以解决这个问题。这是一种非常富有表现力的方法,可以使用BigList找到没有等效SmallList的{​​{1}}元素。

Field1

注意:使用var bigListWithoutSmallList = BigList.Where( b => !SmallList.Any( x => x.Field1 == b.Field1 )); class与您的问题无关。

答案 2 :(得分:0)

一个解决方案可能是实施IEquatable<MyStruct>

 class Program
    {
        static void Main(string[] args)
        {
            var smallList = new List<MyStruct>() { new MyStruct
          {
              Field1="1f",
               Field2 ="2f"
          },
          new MyStruct
          {
              Field1="2f",
               Field2 ="22f"
          }};
            var bigList = new List<MyStruct>() { new MyStruct
          {
              Field1="1f",
               Field2 ="2f"
          },
          new MyStruct
          {
              Field1="3 f",
               Field2 ="22f"
          },new MyStruct
          {
              Field1="4f",
               Field2 ="22f"
          } 
            };


              //find the difference 
            var diffList = smallList.Except(bigList);  

        }
        public struct MyStruct:IEquatable<MyStruct>
        {
            public string Field1;
            public string Field2;

            public bool Equals(MyStruct other)
            {
                if (this.Field1==other.Field1 && this.Field2==other.Field2)
                {
                    return true;   
                }
                return false;   
            }
            public override int GetHashCode()
            {
                return Field1.GetHashCode() & Field2.GetHashCode();
            }
       public override bool Equals(object obj)
        {
            return  this.Equals(obj);
        }
        }
    }

结果可能是带

的结构
       new MyStruct
              {
                  Field1="2f",
                   Field2 ="22f"
              }};

答案 3 :(得分:0)

有一个名为MoreLINQ的开源库,为ExceptBy提供了一个名为IEnumerable<T>的扩展方法,可以满足您的需求。

ExceptBy具有以下签名:

public static IEnumerable<TSource> ExceptBy<TSource, TKey>(
    this IEnumerable<TSource> first, 
    IEnumerable<TSource> second, 
    Func<TSource, TKey> keySelector);

键选择器是一个将源值映射到用于比较的键值的函数,但结果仍然是TSource的序列。

在你的情况下,它将被调用如下:

var Missing = BigList
    .ExceptBy(SmallList, (item => item.fieldToCompareBy)
    .ToList();

与在Contains子句中使用AnyWhere相比,此方法具有相当好的性能。它只需要立即迭代second序列,并且懒惰地从first序列流式传输结果。

答案 4 :(得分:0)

除非在结构中重写Equals,否则将起作用。诀窍是你需要在内部将其视为Nullable。

  brew install node
Updating Homebrew...
To restore the stashed changes to /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core run:
  'cd /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core && git stash pop'
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).
==> New Formulae
gst-rtsp-server
==> Updated Formulae
artifactory         exploitdb           libphonenumber      node@6
aws-sdk-cpp         freetds             llnode              nsd
babl                gimme               mawk                openvpn
bazel               gst-libav           mdv                 rancher-cli
chromedriver        heroku              neofetch            rancher-compose
closure-compiler    jasper              node                riemann
devd                javarepl            node-build          scamper
dovecot             kobalt              node@4              yarn
==> Deleted Formulae
pdksh

==> Downloading https://homebrew.bintray.com/bottles/node-7.2.1.sierra.bottle.ta
######################################################################## 100.0%
==> Pouring node-7.2.1.sierra.bottle.tar.gz
Error: The `brew link` step did not complete successfully
The formula built, but is not symlinked into /usr/local
Could not symlink share/systemtap/tapset/node.stp
Target /usr/local/share/systemtap/tapset/node.stp
already exists. You may want to remove it:
  rm '/usr/local/share/systemtap/tapset/node.stp'

To force the link and overwrite all conflicting files:
  brew link --overwrite node

To list all files that would be deleted:
  brew link --overwrite --dry-run node

Possible conflicting files are:
/usr/local/share/systemtap/tapset/node.stp

==> Using the sandbox
==> Caveats
Please note by default only English locale support is provided. If you need
full locale support you should either rebuild with full icu:
  `brew reinstall node --with-full-icu`
or add full icu data at runtime following:
  https://github.com/nodejs/node/wiki/Intl#using-and-customizing-the-small-icu-build

Bash completion has been installed to: 
/usr/local/etc/bash_completion.d
==> Summary
  /usr/local/Cellar/node/7.2.1: 3,884 files, 45.4M
$ brew link --overwrite node
Linking /usr/local/Cellar/node/7.2.1... 
Error: Could not symlink share/systemtap/tapset/node.stp
/usr/local/share/systemtap/tapset is not writable.