ক্ষেত্রের নামগুলি (স্বেচ্ছাসেবী) দ্বারা কেবল একটি স্ট্রাইকের অ্যারে বাছাই করার সবচেয়ে সংক্ষিপ্ততম উপায় কী?


129

আমার কেবল একটি সমস্যা হয়েছিল যেখানে আমার স্ট্রাক্টগুলির একটি অ্যারে ছিল, যেমন

package main

import "log"

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

func main() {
    var mars = new(Planet)
    mars.Name = "Mars"
    mars.Aphelion = 249.2
    mars.Perihelion = 206.7
    mars.Axis = 227939100
    mars.Radius = 3389.5

    var earth = new(Planet)
    earth.Name = "Earth"
    earth.Aphelion = 151.930
    earth.Perihelion = 147.095
    earth.Axis = 149598261
    earth.Radius = 6371.0

    var venus = new(Planet)
    venus.Name = "Venus"
    venus.Aphelion = 108.939
    venus.Perihelion = 107.477
    venus.Axis = 108208000
    venus.Radius = 6051.8

    planets := [...]Planet{*mars, *venus, *earth}
    log.Println(planets)
}

বলুন আপনি এটি অনুসারে বাছাই করতে চান Axis। তুমি এটা কিভাবে করলে?

(দ্রষ্টব্য: আমি http://golang.org/pkg/sort/ দেখেছি এবং এটি কাজ করছে বলে মনে হচ্ছে, তবে খুব সাধারণ কী দ্বারা সহজ বাছাইয়ের জন্য আমার প্রায় 20 টি লাইন যুক্ত করতে হবে I আমার অজগর ব্যাকগ্রাউন্ডটি যেখানে রয়েছে যতটা সহজ sorted(planets, key=lambda n: n.Axis)- গো-তেও কি তেমন কিছু সহজ?)


এখানে আরও একটি তৃতীয় পক্ষ github.com/patrickmn/sortutil প্যাকেজ। এটি সাধারণ বাছাই করতে পারে এবং নেস্টেড বাছাইও করতে পারে। পারফরম্যান্স সম্পর্কে ডকুমেন্টেশন থেকে এখানে উদ্ধৃতি দিয়েছি: "যদিও সাজ্টুটিল সুবিধাজনক, এটি কোনও উত্সর্গীকৃত বাছাই করবে না performance কার্য সম্পাদনের দিক থেকে ইন্টারফেস sort সাজানো বাস্তবায়ন করছে By (বাইনাম required মাইস্লাইস}) যখন উচ্চ কার্যকারিতা প্রয়োজন হয় তখন বিবেচনা করা উচিত। "
Tutompita

উত্তর:


63

আপডেট: এই উত্তরটি পুরানো সংস্করণগুলির সাথে সম্পর্কিত go। Go 1.8 এবং আরও নতুনদের জন্য , নীচে AndreKR এর উত্তর দেখুন


আপনি যদি স্ট্যান্ডার্ড লাইব্রেরি sortপ্যাকেজের চেয়ে কিছুটা কম ভার্বোস চান তবে আপনি তৃতীয় পক্ষের github.com/bradfitz/sliceপ্যাকেজটি ব্যবহার করতে পারেন । এটি আপনার স্লাইসকে বাছাই করার জন্য প্রয়োজনীয় পদ্ধতি Lenএবং Swapপদ্ধতিগুলি তৈরি করতে কিছু কৌশল ব্যবহার করে , সুতরাং আপনাকে কেবল একটি Lessপদ্ধতি সরবরাহ করতে হবে।

এই প্যাকেজটির সাহায্যে আপনি এর মাধ্যমে বাছাই করতে পারেন:

slice.Sort(planets[:], func(i, j int) bool {
    return planets[i].Axis < planets[j].Axis
})

planets[:]অংশ আপনার অ্যারের আচ্ছাদন একটি ফালি উত্পাদন করা প্রয়োজন। আপনি যদি planetsঅ্যারের পরিবর্তে একটি স্লাইস তৈরি করেন তবে আপনি সেই অংশটি এড়িয়ে যেতে পারেন।


28
একটি অ্যারে বাছাই করতে আমাকে তৃতীয় পক্ষের প্যাকেজটি ব্যবহার করতে হবে (যদি না আমি ভার্বোজ কোডটি অবিশ্বাস্য পরিমাণে লিখতে চাই)? এই ভাষায় ভুল কী? মানে ... এটা ঠিক সাজানো! কোনও কালো যাদু নেই।
জেন্ডাস

8
@ জেন্ডাস গো অর্থ সহজ, সহজ নয়। রুবি সহজ। এমনকি কোনও কিছু কীভাবে কাজ করে তা ঠিক না জানার পরেও আপনি চেষ্টা করতে পারেন এবং এটি প্রত্যাশার মতো কাজ করবে। তবে আপনি ভাষাটির চশমাগুলি বোঝার এবং একটি দোভাষী তৈরি করার চেষ্টা করবেন না, বা রুবি শেখার সময় রেলের কোড পড়ুন। সহজ সরল। আপনাকে পরামর্শ দেওয়া হয়েছে, ট্যুরের পরে, ভাষা সংক্রান্ত বৈশিষ্ট্য পড়ার জন্য - এমনকি নবজাতকরাও পারেন। এবং তারা সর্বাধিক উন্নত কোড পড়তে এবং এটি পেতে পারে। কারণ এটি সহজ।
কিক

4
@kik- এর কোন মানে নেই। সরল অর্থ বৈশিষ্ট্যহীন নয়। বাছাই করা সবচেয়ে গুরুত্বপূর্ণ এবং মৌলিক, তবুও একটি সাধারণ বৈশিষ্ট্য যা কোনও গ্রন্থাগারের থাকতে পারে। গোলংয়ের এইচটিএমএল টেমপ্লেট, সিআরসি 32 হ্যাশ, প্রিন্টার, স্ক্যানার ইত্যাদির জন্য একটি স্ট্যান্ডার্ড লাইব্রেরি রয়েছে যা এটিকে কম সহজ করে না। আপনার স্ট্যান্ডার্ড লাইব্রেরিতে বাছাই না করা সরলতার বিষয় নয়, সমস্ত ভাষা একটি স্ট্যান্ডার্ড হিসাবে বিবেচিত ফান্ডামেন্টাল বৈশিষ্ট্যের বিষয়। এমনকি সি একটি বাছাই ফাংশন আছে। গোলাংয়ের সাথে এতটা অভিজাত শ্রেণীর হয়ে যাওয়া বন্ধ করুন এবং এই বিবেচনা করা শুরু করুন যে গোলং এই একজনের পক্ষে ঠিক ভুল হতে পারে (যদি তা আসলে না থাকে)।
একসাপ্সি

318

যান 1.8 এর হিসাবে আপনি এখন ব্যবহার করতে পারেন sort.Slice একটি ফালি সাজাতে:

sort.Slice(planets, func(i, j int) bool {
  return planets[i].Axis < planets[j].Axis
})

সেখানে স্বাভাবিকভাবে একটি ফালি পরিবর্তে একটি অ্যারের ব্যবহার করার কোনও কারণ, কিন্তু আপনার উদাহরণে আপনি হয় একটি অ্যারে ব্যবহার করে, তাই আপনি একটি ফালি (অ্যাড দিয়ে ওভারলে আছে [:]) করতে এটা দিয়ে কাজ sort.Slice:

sort.Slice(planets[:], func(i, j int) bool {
  return planets[i].Axis < planets[j].Axis
})

বাছাইয়ের ফলে অ্যারে পরিবর্তন হয়, সুতরাং আপনি যদি সত্যিই চান তবে আপনি বাছাইয়ের পরে স্লাইসের পরিবর্তে অ্যারে ব্যবহার চালিয়ে যেতে পারেন।


sort.Sliceবিস্ময়কর এক ধরণের। lessফাংশন শুধুমাত্র সূচকগুলি লাগে তাই এটা করার জন্য (এই উত্তর) একটি আলাদাভাবে-বন্দী ব্যবহার হয়েছে planetsঅ্যারে। সাজানো টুকরা এবং lessফাংশন একই ডেটাতে কাজ করছে এমন বলবৎ করার মতো কিছু নেই বলে মনে হচ্ছে । এটি কাজ করার জন্য আপনাকে planetsতিনবার টাইপ করতে হবে (ডিআরওয়াই)।
ব্রেন্ট ব্র্যাডবার্ন

planets[:]অত্যন্ত গুরুত্বপূর্ণ. তবে আমি বুঝতে পারি না কেন। যদিও কাজ করে।
স্টিল

@ স্টিল সাধারণত আপনার প্রথম স্থানে অ্যারের পরিবর্তে একটি স্লাইস ব্যবহার করা উচিত। তাহলে আপনার দরকার নেই [:]
AndreKR

37

Go 1.8 হিসাবে, @ AndreKR এর উত্তর হ'ল আরও ভাল সমাধান।


আপনি একটি সংগ্রহের ধরণ প্রয়োগ করতে পারেন যা সাজানোর ইন্টারফেস প্রয়োগ করে ।

এখানে এই জাতীয় দুটি ধরণের একটি উদাহরণ যা আপনাকে অক্ষ বা নাম অনুসারে বাছাই করতে দেয়:

package main

import "log"
import "sort"

// AxisSorter sorts planets by axis.
type AxisSorter []Planet

func (a AxisSorter) Len() int           { return len(a) }
func (a AxisSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a AxisSorter) Less(i, j int) bool { return a[i].Axis < a[j].Axis }

// NameSorter sorts planets by name.
type NameSorter []Planet

func (a NameSorter) Len() int           { return len(a) }
func (a NameSorter) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a NameSorter) Less(i, j int) bool { return a[i].Name < a[j].Name }

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

func main() {
    var mars Planet
    mars.Name = "Mars"
    mars.Aphelion = 249.2
    mars.Perihelion = 206.7
    mars.Axis = 227939100
    mars.Radius = 3389.5

    var earth Planet
    earth.Name = "Earth"
    earth.Aphelion = 151.930
    earth.Perihelion = 147.095
    earth.Axis = 149598261
    earth.Radius = 6371.0

    var venus Planet
    venus.Name = "Venus"
    venus.Aphelion = 108.939
    venus.Perihelion = 107.477
    venus.Axis = 108208000
    venus.Radius = 6051.8

    planets := []Planet{mars, venus, earth}
    log.Println("unsorted:", planets)

    sort.Sort(AxisSorter(planets))
    log.Println("by axis:", planets)

    sort.Sort(NameSorter(planets))
    log.Println("by name:", planets)
}

এটি হ'ল ভার্জোজ সলিউশনটি আমি যুক্ত করেছি, তাই না?
মার্টিন থোমা

1
আমি এটি লেখার সময় আপনি এটি যুক্ত করেছিলেন। আমার ক্ষমা। তবে কেবলমাত্র মানক সরঞ্জামগুলি ব্যবহার করে, এটি করার কোনও ছোট উপায় নেই।
jimt

5

আপনি পরিবর্তে বাস্তবায়নের পারেন Sort interfaceউপর []Planetআপনি একটি যে ধরনের সংগ্রহ ও একটি অবসান যে তুলনা কি করতে হবে ধারণ উপর বাস্তবায়ন। প্রতিটি সম্পত্তির তুলনা বন্ধের জন্য আপনাকে বাস্তবায়ন সরবরাহ করতে হবে।

স্ট্রাক্টের প্রতিটি সম্পত্তির জন্য বাছাই করার ধরণের প্রয়োগের চেয়ে এই পদ্ধতিটি আমি অনুভব করি।

এই উত্তরটি প্রায় সঠিকভাবে সাজানো ডক্স থেকে ছিঁড়ে গেছে তাই আমি এর জন্য খুব বেশি ক্রেডিট নিতে পারি না

package main

import (
    "log"
    "sort"
)

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

type By func(p1, p2 *Planet) bool

func (by By) Sort(planets []Planet) {
    ps := &planetSorter{
        planets: planets,
        by:      by, 
    }
    sort.Sort(ps)
}

type planetSorter struct {
    planets []Planet
    by      func(p1, p2 *Planet) bool 
}

func (s *planetSorter) Len() int {
    return len(s.planets)
}

func (s *planetSorter) Swap(i, j int) {
    s.planets[i], s.planets[j] = s.planets[j], s.planets[i]
}

func (s *planetSorter) Less(i, j int) bool {
    return s.by(&s.planets[i], &s.planets[j])
}

কিভাবে এটি কল।

func main() {
    /* Same code as in the question */

    planets := []Planet{*mars, *venus, *earth}

    By(func(p1, p2 *Planet) bool {
        return p1.Name < p2.Name
    }).Sort(planets)

    log.Println(planets)

    By(func(p1, p2 *Planet) bool {
        return p1.Axis < p2.Axis
    }).Sort(planets)

    log.Println(planets)
}

এখানে একটি ডেমো রয়েছে


3

এখানে কিছু বয়লার প্লেট হ্রাস করার অন্য উপায়। দাবি অস্বীকার, এটি প্রতিবিম্ব এবং ক্ষতির ধরণের সুরক্ষা ব্যবহার করে।

এখানে একটি ডেমো রয়েছে

সমস্ত যাদু Propফাংশন ঘটে । এটি স্ট্রাক্ট সম্পত্তিটি বাছাই করতে এবং যাতে আপনি সাজানোর (ক্রমবর্ধমান, অবতরণ) করতে চান সেটি লাগে এবং একটি ফাংশন দেয় যা তুলনা সম্পাদন করবে।

package main

import (
    "log"
    "reflect"
    "sort"
)

func test(planets []Planet) {
    log.Println("Sort Name")
    By(Prop("Name", true)).Sort(planets)
    log.Println(planets)

    log.Println("Sort Aphelion")
    By(Prop("Aphelion", true)).Sort(planets)
    log.Println(planets)

    log.Println("Sort Perihelion")
    By(Prop("Perihelion", true)).Sort(planets)
    log.Println(planets)

    log.Println("Sort Axis")
    By(Prop("Axis", true)).Sort(planets)
    log.Println(planets)

    log.Println("Sort Radius")
    By(Prop("Radius", true)).Sort(planets)
    log.Println(planets)
}

func Prop(field string, asc bool) func(p1, p2 *Planet) bool {
    return func(p1, p2 *Planet) bool {

        v1 := reflect.Indirect(reflect.ValueOf(p1)).FieldByName(field)
        v2 := reflect.Indirect(reflect.ValueOf(p2)).FieldByName(field)

        ret := false

        switch v1.Kind() {
        case reflect.Int64:
            ret = int64(v1.Int()) < int64(v2.Int())
        case reflect.Float64:
            ret = float64(v1.Float()) < float64(v2.Float())
        case reflect.String:
            ret = string(v1.String()) < string(v2.String())
        }

        if asc {
            return ret
        }
        return !ret
    }
}

type Planet struct {
    Name       string  `json:"name"`
    Aphelion   float64 `json:"aphelion"`   // in million km
    Perihelion float64 `json:"perihelion"` // in million km
    Axis       int64   `json:"Axis"`       // in km
    Radius     float64 `json:"radius"`
}

type By func(p1, p2 *Planet) bool

func (by By) Sort(planets []Planet) {
    ps := &planetSorter{
        planets: planets,
        by:      by, // The Sort method's receiver is the function (closure) that defines the sort order.
    }
    sort.Sort(ps)
}

type planetSorter struct {
    planets []Planet
    by      func(p1, p2 *Planet) bool // Closure used in the Less method.
}

// Len is part of sort.Interface.
func (s *planetSorter) Len() int { return len(s.planets) }

// Swap is part of sort.Interface.
func (s *planetSorter) Swap(i, j int) {
    s.planets[i], s.planets[j] = s.planets[j], s.planets[i]
}

// Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.
func (s *planetSorter) Less(i, j int) bool {
    return s.by(&s.planets[i], &s.planets[j])
}

func main() {
    test(dataSet())
}

func dataSet() []Planet {

    var mars = new(Planet)
    mars.Name = "Mars"
    mars.Aphelion = 249.2
    mars.Perihelion = 206.7
    mars.Axis = 227939100
    mars.Radius = 3389.5

    var earth = new(Planet)
    earth.Name = "Earth"
    earth.Aphelion = 151.930
    earth.Perihelion = 147.095
    earth.Axis = 149598261
    earth.Radius = 6371.0

    var venus = new(Planet)
    venus.Name = "Venus"
    venus.Aphelion = 108.939
    venus.Perihelion = 107.477
    venus.Axis = 108208000
    venus.Radius = 6051.8

    return []Planet{*mars, *venus, *earth}
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.