计㈡愣

文章 评论 浏览 26

计㈡愣 2025-02-21 00:14:08

使用实体框架,是否有一种简单干净的方法将“或”条件添加到动态生成的查询中?

是的,您可以通过简单地依靠一个子句,其中包含一个单个布尔表达式,其 parts在运行时动态“禁用”或“启用”,因此,避免必须安装linqkit或编写自定义谓词构建器。

参考您的示例:

var isFirstValid = !string.IsNullOrWhiteSpace(first);
var isLastValid = !string.IsNullOrWhiteSpace(last);

var query = db.Names
  .AsQueryable()
  .Where(name =>
    (isFirstValid && name.first.Contains(first)) ||
    (isLastValid && name.last.Contains(last))
  )
  .ToList();

如上所述,我们正在动态切换> -filter表达式基于先前评估的前提的 - 零件(例如)(例如 isfirstValid )。

例如,如果 iSfirstValid 不是 true ,则 name.first.contains(first) is 短路,既不会执行也不会影响结果集。此外,EF Core的 defaultquerysqlgenerator 将进一步优化并减少 内部的布尔表达式在执行之前(例如false&&& x || true&& y y || && z 可以通过简单的静态分析简单地 )。

请注意:如果这些前提都不是 true ,那么结果集将是空的 - 我认为这是您的情况下的所需行为。但是,如果您出于某种原因而不是从 iQueryable 源中选择所有元素,则可以将最终变量添加到 true (例如)中。 。

最后一句话:该技术的缺点是,它迫使您构建一个位于您查询所在的相同方法的“集中”布尔表达式(更准确地说是,其中 查询的一部分)。如果您出于某种原因想将谓词的构建过程分散,并通过查询构建器将其注入参数或将其注入参数,那么您应该最好坚持使用其他答案中建议的谓词构建器。否则,请享受这种简单的技术:)

Is there a simple and clean way to add "OR" conditions to a dynamically generated query using entity framework?

Yes, you can achieve this by simply relying on a single where clause containing a single boolean expression whose OR parts are "disabled" or "enabled" dynamically at runtime, thus, avoiding having to install LINQKit or writing a custom predicate builder.

In reference to your example:

var isFirstValid = !string.IsNullOrWhiteSpace(first);
var isLastValid = !string.IsNullOrWhiteSpace(last);

var query = db.Names
  .AsQueryable()
  .Where(name =>
    (isFirstValid && name.first.Contains(first)) ||
    (isLastValid && name.last.Contains(last))
  )
  .ToList();

As you can see in the example above, we are dynamically switching "on" or "off" the OR-parts of the where-filter expression based on previously evaluated premises (e.g isFirstValid).

For example if isFirstValid is not true, then name.first.Contains(first) is short-circuited and will neither be executed nor affect the resultset. Moreover, EF Core's DefaultQuerySqlGenerator will further optimize and reduce the boolean expression inside where before executing it (e.g. false && x || true && y || false && z may be reduced to simply y through simple static analysis).

Please note: If none of the premises are true, then the result-set will be empty – which I assume is the desired behavior in your case. However, if you for some reason rather prefer to select all elements from your IQueryable source, then you may add a final variable to the expression evaluating to true (e.g. .Where( ... || shouldReturnAll) with var shouldReturnAll = !(isFirstValid || isLastValid) or something similar).

A final remark: The downside of this technique is that it forces you to build a "centralized" boolean expression that resides in the same method body in which your query lies (more precisely the where part of the query). If you, for some reason, want to decentralize the build process of your predicates and inject them as arguments or chain them via the query builder, then you should better stick with a predicate builder as suggested in the other answers. Otherwise, enjoy this simple technique :)

通过实体框架中的或条件的动态查询

计㈡愣 2025-02-20 22:46:05

您可以使用

package com.joon.fm.core.base.genericRecycler


import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import androidx.core.util.set
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.joon.fm.core.extensions.getClass
import com.joon.fm.features.explore.section.SectionExploreNewReleases
import java.lang.reflect.Constructor
import java.util.concurrent.atomic.AtomicInteger


interface GenericAdapterView<Model> {
    fun onBind(model: Model, position: Int, extraObject: Any?)
}

data class Section<Model>(
    var type: Int,
    var data: Model,
    var extraObject: Any?,
    var index: Int = -1
)

open class VH(view: View) : RecyclerView.ViewHolder(view)

interface DiffUtilModel {
    fun areItemsTheSame(o: DiffUtilModel): Boolean
    fun areContentsTheSame(o: DiffUtilModel): Boolean
}

class MyDiffCallback(private val oldList: List<Any?>, private val newList: List<Any?>) :
    DiffUtil.Callback() {
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val old = oldList[oldItemPosition]
        val new = newList[newItemPosition]
        if (old is DiffUtilModel && new is DiffUtilModel) {
            return old.areItemsTheSame(new)
        }
        return oldList[oldItemPosition] == newList[newItemPosition]
    }

    override fun getOldListSize() = oldList.size

    override fun getNewListSize() = newList.size

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val old = oldList[oldItemPosition]
        val new = newList[newItemPosition]
        if (old is DiffUtilModel && new is DiffUtilModel) {
            return old.areContentsTheSame(new)
        }
        return (old == null && new == null) || (old != null && old == new)
    }

}

@Suppress("unused")
open class AppGenericAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    val sections = ArrayList<Section<*>>()
    var providers = SparseArray<(ViewGroup, Int) -> View>()

    private var types = HashMap<Class<*>, Pair<Int, Constructor<*>?>>()
    private var typeIds = AtomicInteger(0)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return VH(providers[viewType](parent, viewType))
    }


    @Suppress("UNCHECKED_CAST")
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val v = holder.itemView as? GenericAdapterView<Any>
        val sec = sections[position]
        sec.data?.run {
            v?.onBind(this, position, sec.extraObject)
        }
    }

    override fun getItemCount() = sections.size
    override fun getItemViewType(position: Int) = sections[position].type


    inline fun <reified V : View> viewType(addDefaultProvider: Boolean = true) =
        viewType(V::class.java, addDefaultProvider)

    fun viewType(cls: Class<*>, addDefaultProvider: Boolean = true): Int {
        val prevAns = types[cls]
        if (prevAns == null) {
            var cons: Constructor<*>? = null
            try {
                cons = cls.getDeclaredConstructor(Context::class.java)
            } catch (ignored: Throwable) {
            }
            types[cls] = Pair(typeIds.getAndIncrement(), cons)

            val type = types[cls]!!

            if (addDefaultProvider && providers[type.first] == null) {
                providers[type.first] = { vg, _ ->
                    type.second!!.newInstance(vg.context) as View
                }

            }
            return type.first
        } else {
            return prevAns.first
        }
    }


    inline fun <reified V> setProvider(noinline provider: (ViewGroup, Int) -> V) where V : View, V : GenericAdapterView<*> {
        providers[viewType<V>(false)] = provider
    }

    inline fun <reified V> provider(noinline provider: (Context) -> V) where V : View, V : GenericAdapterView<*> {
        providers[viewType<V>(false)] = { vg, _ -> provider(vg.context) }
    }

    inline fun <reified V> addProvider(noinline provider: (Context) -> V) where V : View, V : GenericAdapterView<*> {
        providers.set(viewType<V>(false)) { vg, _ -> provider(vg.context) }
    }


    inline fun <reified V, reified Model : Any> setSections(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.clear()
        addSections<V, Model>(data, extra)
    }

    inline fun <reified V, reified Model : Any> setSectionsDiffUtil(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {

        val diffCallback = MyDiffCallback(sections.map { it.data }, data.toList())
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        sections.clear()
        addSections<V, Model>(data, extra)
        diffResult.dispatchUpdatesTo(this)

    }

    fun setSectionsDiffUtil(newSections: Collection<Section<*>>) {
        val diffCallback = MyDiffCallback(sections.map { it.data }, newSections.map { it.data })
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        sections.clear()
        sections.addAll(newSections)
        diffResult.dispatchUpdatesTo(this)
    }

    inline fun <reified V, reified Model : Any> setSectionsAndNotify(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        setSections<V, Model>(data, extra)
        notifyDataSetChanged()
    }
    fun  removeItemFromSectionsAndNotify(
        index: Int,
    ) {
        sections.removeAt(index)
        notifyDataSetChanged()
    }

    inline fun <reified V, reified Model : Any> setSectionsAndNotifyRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val prevSize = itemCount
        setSections<V, Model>(data, extra)
        val newSize = itemCount
        notifyItemRangeChanged(0, newSize)
        if (prevSize > newSize) {
            notifyItemRangeRemoved(newSize, prevSize - newSize)
        }
    }


    inline fun <reified V, reified Model : Any> addSections(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val type = viewType<V>()
        sections.addAll(data.map { Section(type, it, extra) })
    }

    inline fun <reified V> addView(
    ) where V : View {
        val type = viewType<V>()
        sections.add(Section(viewType<V>(), null, null))
    }

    inline fun <reified V, reified Model : Any> addSectionsAndNotify(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyDataSetChanged()
    }

    inline fun <reified V, reified Model : Any> addSectionsAndNotifyRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyItemRangeChanged(itemCount - data.size, itemCount)
    }
    inline fun <reified V, reified Model : Any> addSectionsAndNotifyCompleteRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyItemRangeChanged(itemCount - data.size, itemCount)
    }


    inline fun <reified V, reified Model : Any?> setSection(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections[position] = Section(viewType<V>(), data, extra)
    }

    inline fun <reified V, reified Model : Any?> setSectionAndNotify(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        setSection<V, Model>(position, data, extra)
        notifyItemChanged(position)
    }

    fun updateSection(
        position: Int,
    ) {
        notifyItemChanged(position)
        Handler(Looper.getMainLooper()).post {
            notifyItemChanged(position)
        }
    }
    
    inline fun <reified V, reified Model : Any> addSection(
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.add(Section(viewType<V>(), data, extra))
    }

    inline fun <reified V, reified Model : Any> addSectionAndNotify(
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSection<V, Model>(data, extra)
        notifyItemInserted(sections.size - 1)
    }

    inline fun <reified V, reified Model : Any?> createEmptySection(
        data: Model?,
        extra: Any? = null
    ): Section<Model?> where V : View, V : GenericAdapterView<Model> =
        Section(viewType<V>(), data, extra)

    inline fun <reified V, reified Model : Any> createSection(
        data: Model,
        extra: Any? = null
    ): Section<Model> where V : View, V : GenericAdapterView<Model> =
        Section(viewType<V>(), data, extra)


    inline fun <reified V, reified Model : Any> addSection(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.add(position, Section(viewType<V>(), data, extra))
    }

    inline fun <reified V, reified Model : Any?> addEmpotySection(
        position: Int,
        data: Model? = null,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val type = viewType<V>()
        if (sections.find { it.type == type } != null) {
            sections.add(position, Section(viewType<V>(), data, extra))
            val index = sections.indexOfLast { it.type == type }
            providers.delete(index)
            sections.removeAt(index)
            notifyItemRangeChanged(index-1,1)
        } else {
            sections.add(position, Section(viewType<V>(), data, extra))
            notifyItemInserted(position)
        }
    }

    inline fun <reified V, reified Model : Any> addSectionAndNotify(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSection<V, Model>(position, data, extra)
        notifyItemInserted(position)
    }


    inline fun <reified V, reified Model : Any> createSections(
        data: Collection<Model>,
        extra: Any? = null
    ): List<Section<Model>> where V : View, V : GenericAdapterView<Model> =
        data.map { Section(viewType<V>(), it, extra) }


    fun createSection(
        cls: Class<*>,
        data: Any,
        extra: Any? = null
    ): Section<*> =
        Section(viewType(cls), data, extra)


    fun clearData() {
        sections.clear()
    }

    fun clearDataAndNotify() {
        sections.clear()
        providers.clear()
        notifyDataSetChanged()
    }

    inline fun <reified V : View> clearViews() {
        val type = viewType<V>()
        sections.removeAll { it.type == type }
    }

    inline fun <reified V : View> findIndexItem(): Int {
        val type = viewType<V>()
        var item = 0
        sections.forEachIndexed { index, section ->
            if (section.type == type) {
                item = index
            }
        }
        return item
    }

    inline fun <reified V : View> findIndexItemNew(): Int? {
        val type = viewType<V>()
        var item: Int? = null
        sections.forEachIndexed { index, section ->
            if (section.type == type) {
                item = index
            }
        }
        return item
    }

    inline fun <reified V : View> clearSectionsWithTypeAndNotify() {
        clearViews<V>()
        notifyItemRemoved(viewType<V>(false))
        providers.delete(viewType<V>(false))
    }

    inline fun <reified T> sectionsWithType(): List<Section<T>> =
        sections.mapIndexed { index, section -> section.index = index; section }
            .filter { it.data is T }.map { it as Section<T> }

}

fun AppGenericAdapter.setSectionsInViewsListAndTryToRecycle(
    parent: ViewGroup,
    lpProvider: (AppGenericAdapter.(Section<*>, Int) -> ViewGroup.LayoutParams)? = null
) {
    for (i in 0 until sections.size) {
        val section = sections[i]
        if (i < parent.childCount) {
            try {
                val child = parent.getChildAt(i) as GenericAdapterView<Any>
                child.onBind(section.data as Any, i, section.extraObject)
            } catch (e: Exception) {
                parent.removeAllViews()
                setSectionsInViewsListAndTryToRecycle(parent)
            }
        } else {
            val vh = onCreateViewHolder(parent, section.type)
            if (vh.itemView is GenericAdapterView<*>) {
                (vh.itemView as GenericAdapterView<Any>).onBind(
                    section.data!!,
                    i,
                    section.extraObject
                )
            }
            if (lpProvider != null) {
                vh.itemView.layoutParams = lpProvider(section, i)
            }
            parent.addView(vh.itemView)
        }
    }
    if (parent.childCount - sections.size > 0) {
        parent.removeViews(sections.size, parent.childCount - sections.size)
    }
}

这是一个通用适配器类,可以在简单适配器的所有项目实例中使用。您只需添加一个项目并将其传递给通用类即可创建您的列表。

如何用户
首先,您必须将此课程添加到您的项目中。

abstract class BaseCustomView<viewDataBinding : ViewDataBinding> @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
    lateinit var binding: viewDataBinding

    init {
        this.inflate(context, attrs)
    }

    @CallSuper
    protected open fun inflate(context: Context, attrs: AttributeSet?){

        val bindingClass = javaClass.findGenericWithType<viewDataBinding>(ViewDataBinding::class.java)

        if(isInEditMode){
            if(bindingClass != null){
                val resId = bindingClass.layoutId(context)
                LayoutInflater.from(context).inflate(resId, this, true)
            }
        } else {
            binding = bindingClass?.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)?.invoke(null, LayoutInflater.from(context), this, true) as viewDataBinding
            binding.setView(this)
        }
    }


}

之后,您的项目(VH)必须像这样继承此类

class YourItem @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : BaseCustomView<YouBinding>(context, attrs, defStyleAttr),
    GenericAdapterView<Model> {
    override fun onBind(model: Model, position: Int, extraObject: Any?) {
    }
}

,最后将项目附加到适配器

private val adapter = AppGenericAdapter().apply {
    provider { context ->
        YourItem (context,)// if you want to pass extra data you can pass data as arg
    }
    provider { context ->
        YourItemButton(context,)// if you want to pass extra data you can pass data as arg
    }
}

binding.recycler.adapter = adapter
adapter.addSectionsAndNotify<YourItem , Model>(data)
// you can check with if the last item add this item
adapter.addSectionsAndNotify<YourItemButton , Model>(data)

You can use this

package com.joon.fm.core.base.genericRecycler


import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import androidx.core.util.set
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.joon.fm.core.extensions.getClass
import com.joon.fm.features.explore.section.SectionExploreNewReleases
import java.lang.reflect.Constructor
import java.util.concurrent.atomic.AtomicInteger


interface GenericAdapterView<Model> {
    fun onBind(model: Model, position: Int, extraObject: Any?)
}

data class Section<Model>(
    var type: Int,
    var data: Model,
    var extraObject: Any?,
    var index: Int = -1
)

open class VH(view: View) : RecyclerView.ViewHolder(view)

interface DiffUtilModel {
    fun areItemsTheSame(o: DiffUtilModel): Boolean
    fun areContentsTheSame(o: DiffUtilModel): Boolean
}

class MyDiffCallback(private val oldList: List<Any?>, private val newList: List<Any?>) :
    DiffUtil.Callback() {
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val old = oldList[oldItemPosition]
        val new = newList[newItemPosition]
        if (old is DiffUtilModel && new is DiffUtilModel) {
            return old.areItemsTheSame(new)
        }
        return oldList[oldItemPosition] == newList[newItemPosition]
    }

    override fun getOldListSize() = oldList.size

    override fun getNewListSize() = newList.size

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
        val old = oldList[oldItemPosition]
        val new = newList[newItemPosition]
        if (old is DiffUtilModel && new is DiffUtilModel) {
            return old.areContentsTheSame(new)
        }
        return (old == null && new == null) || (old != null && old == new)
    }

}

@Suppress("unused")
open class AppGenericAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    val sections = ArrayList<Section<*>>()
    var providers = SparseArray<(ViewGroup, Int) -> View>()

    private var types = HashMap<Class<*>, Pair<Int, Constructor<*>?>>()
    private var typeIds = AtomicInteger(0)

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return VH(providers[viewType](parent, viewType))
    }


    @Suppress("UNCHECKED_CAST")
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val v = holder.itemView as? GenericAdapterView<Any>
        val sec = sections[position]
        sec.data?.run {
            v?.onBind(this, position, sec.extraObject)
        }
    }

    override fun getItemCount() = sections.size
    override fun getItemViewType(position: Int) = sections[position].type


    inline fun <reified V : View> viewType(addDefaultProvider: Boolean = true) =
        viewType(V::class.java, addDefaultProvider)

    fun viewType(cls: Class<*>, addDefaultProvider: Boolean = true): Int {
        val prevAns = types[cls]
        if (prevAns == null) {
            var cons: Constructor<*>? = null
            try {
                cons = cls.getDeclaredConstructor(Context::class.java)
            } catch (ignored: Throwable) {
            }
            types[cls] = Pair(typeIds.getAndIncrement(), cons)

            val type = types[cls]!!

            if (addDefaultProvider && providers[type.first] == null) {
                providers[type.first] = { vg, _ ->
                    type.second!!.newInstance(vg.context) as View
                }

            }
            return type.first
        } else {
            return prevAns.first
        }
    }


    inline fun <reified V> setProvider(noinline provider: (ViewGroup, Int) -> V) where V : View, V : GenericAdapterView<*> {
        providers[viewType<V>(false)] = provider
    }

    inline fun <reified V> provider(noinline provider: (Context) -> V) where V : View, V : GenericAdapterView<*> {
        providers[viewType<V>(false)] = { vg, _ -> provider(vg.context) }
    }

    inline fun <reified V> addProvider(noinline provider: (Context) -> V) where V : View, V : GenericAdapterView<*> {
        providers.set(viewType<V>(false)) { vg, _ -> provider(vg.context) }
    }


    inline fun <reified V, reified Model : Any> setSections(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.clear()
        addSections<V, Model>(data, extra)
    }

    inline fun <reified V, reified Model : Any> setSectionsDiffUtil(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {

        val diffCallback = MyDiffCallback(sections.map { it.data }, data.toList())
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        sections.clear()
        addSections<V, Model>(data, extra)
        diffResult.dispatchUpdatesTo(this)

    }

    fun setSectionsDiffUtil(newSections: Collection<Section<*>>) {
        val diffCallback = MyDiffCallback(sections.map { it.data }, newSections.map { it.data })
        val diffResult = DiffUtil.calculateDiff(diffCallback)
        sections.clear()
        sections.addAll(newSections)
        diffResult.dispatchUpdatesTo(this)
    }

    inline fun <reified V, reified Model : Any> setSectionsAndNotify(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        setSections<V, Model>(data, extra)
        notifyDataSetChanged()
    }
    fun  removeItemFromSectionsAndNotify(
        index: Int,
    ) {
        sections.removeAt(index)
        notifyDataSetChanged()
    }

    inline fun <reified V, reified Model : Any> setSectionsAndNotifyRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val prevSize = itemCount
        setSections<V, Model>(data, extra)
        val newSize = itemCount
        notifyItemRangeChanged(0, newSize)
        if (prevSize > newSize) {
            notifyItemRangeRemoved(newSize, prevSize - newSize)
        }
    }


    inline fun <reified V, reified Model : Any> addSections(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val type = viewType<V>()
        sections.addAll(data.map { Section(type, it, extra) })
    }

    inline fun <reified V> addView(
    ) where V : View {
        val type = viewType<V>()
        sections.add(Section(viewType<V>(), null, null))
    }

    inline fun <reified V, reified Model : Any> addSectionsAndNotify(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyDataSetChanged()
    }

    inline fun <reified V, reified Model : Any> addSectionsAndNotifyRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyItemRangeChanged(itemCount - data.size, itemCount)
    }
    inline fun <reified V, reified Model : Any> addSectionsAndNotifyCompleteRange(
        data: Collection<Model>,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSections<V, Model>(data, extra)
        notifyItemRangeChanged(itemCount - data.size, itemCount)
    }


    inline fun <reified V, reified Model : Any?> setSection(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections[position] = Section(viewType<V>(), data, extra)
    }

    inline fun <reified V, reified Model : Any?> setSectionAndNotify(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        setSection<V, Model>(position, data, extra)
        notifyItemChanged(position)
    }

    fun updateSection(
        position: Int,
    ) {
        notifyItemChanged(position)
        Handler(Looper.getMainLooper()).post {
            notifyItemChanged(position)
        }
    }
    
    inline fun <reified V, reified Model : Any> addSection(
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.add(Section(viewType<V>(), data, extra))
    }

    inline fun <reified V, reified Model : Any> addSectionAndNotify(
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSection<V, Model>(data, extra)
        notifyItemInserted(sections.size - 1)
    }

    inline fun <reified V, reified Model : Any?> createEmptySection(
        data: Model?,
        extra: Any? = null
    ): Section<Model?> where V : View, V : GenericAdapterView<Model> =
        Section(viewType<V>(), data, extra)

    inline fun <reified V, reified Model : Any> createSection(
        data: Model,
        extra: Any? = null
    ): Section<Model> where V : View, V : GenericAdapterView<Model> =
        Section(viewType<V>(), data, extra)


    inline fun <reified V, reified Model : Any> addSection(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        sections.add(position, Section(viewType<V>(), data, extra))
    }

    inline fun <reified V, reified Model : Any?> addEmpotySection(
        position: Int,
        data: Model? = null,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        val type = viewType<V>()
        if (sections.find { it.type == type } != null) {
            sections.add(position, Section(viewType<V>(), data, extra))
            val index = sections.indexOfLast { it.type == type }
            providers.delete(index)
            sections.removeAt(index)
            notifyItemRangeChanged(index-1,1)
        } else {
            sections.add(position, Section(viewType<V>(), data, extra))
            notifyItemInserted(position)
        }
    }

    inline fun <reified V, reified Model : Any> addSectionAndNotify(
        position: Int,
        data: Model,
        extra: Any? = null
    ) where V : View, V : GenericAdapterView<Model> {
        addSection<V, Model>(position, data, extra)
        notifyItemInserted(position)
    }


    inline fun <reified V, reified Model : Any> createSections(
        data: Collection<Model>,
        extra: Any? = null
    ): List<Section<Model>> where V : View, V : GenericAdapterView<Model> =
        data.map { Section(viewType<V>(), it, extra) }


    fun createSection(
        cls: Class<*>,
        data: Any,
        extra: Any? = null
    ): Section<*> =
        Section(viewType(cls), data, extra)


    fun clearData() {
        sections.clear()
    }

    fun clearDataAndNotify() {
        sections.clear()
        providers.clear()
        notifyDataSetChanged()
    }

    inline fun <reified V : View> clearViews() {
        val type = viewType<V>()
        sections.removeAll { it.type == type }
    }

    inline fun <reified V : View> findIndexItem(): Int {
        val type = viewType<V>()
        var item = 0
        sections.forEachIndexed { index, section ->
            if (section.type == type) {
                item = index
            }
        }
        return item
    }

    inline fun <reified V : View> findIndexItemNew(): Int? {
        val type = viewType<V>()
        var item: Int? = null
        sections.forEachIndexed { index, section ->
            if (section.type == type) {
                item = index
            }
        }
        return item
    }

    inline fun <reified V : View> clearSectionsWithTypeAndNotify() {
        clearViews<V>()
        notifyItemRemoved(viewType<V>(false))
        providers.delete(viewType<V>(false))
    }

    inline fun <reified T> sectionsWithType(): List<Section<T>> =
        sections.mapIndexed { index, section -> section.index = index; section }
            .filter { it.data is T }.map { it as Section<T> }

}

fun AppGenericAdapter.setSectionsInViewsListAndTryToRecycle(
    parent: ViewGroup,
    lpProvider: (AppGenericAdapter.(Section<*>, Int) -> ViewGroup.LayoutParams)? = null
) {
    for (i in 0 until sections.size) {
        val section = sections[i]
        if (i < parent.childCount) {
            try {
                val child = parent.getChildAt(i) as GenericAdapterView<Any>
                child.onBind(section.data as Any, i, section.extraObject)
            } catch (e: Exception) {
                parent.removeAllViews()
                setSectionsInViewsListAndTryToRecycle(parent)
            }
        } else {
            val vh = onCreateViewHolder(parent, section.type)
            if (vh.itemView is GenericAdapterView<*>) {
                (vh.itemView as GenericAdapterView<Any>).onBind(
                    section.data!!,
                    i,
                    section.extraObject
                )
            }
            if (lpProvider != null) {
                vh.itemView.layoutParams = lpProvider(section, i)
            }
            parent.addView(vh.itemView)
        }
    }
    if (parent.childCount - sections.size > 0) {
        parent.removeViews(sections.size, parent.childCount - sections.size)
    }
}

This is a Generic adapter class you can use in all project instances of a simple adapter. you just add an item and pass to the generic class to create your list.

How to User
First of all, you must add this class to your project.

abstract class BaseCustomView<viewDataBinding : ViewDataBinding> @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
    lateinit var binding: viewDataBinding

    init {
        this.inflate(context, attrs)
    }

    @CallSuper
    protected open fun inflate(context: Context, attrs: AttributeSet?){

        val bindingClass = javaClass.findGenericWithType<viewDataBinding>(ViewDataBinding::class.java)

        if(isInEditMode){
            if(bindingClass != null){
                val resId = bindingClass.layoutId(context)
                LayoutInflater.from(context).inflate(resId, this, true)
            }
        } else {
            binding = bindingClass?.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java)?.invoke(null, LayoutInflater.from(context), this, true) as viewDataBinding
            binding.setView(this)
        }
    }


}

after that, your item (VH), must inheritance this class like this

class YourItem @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : BaseCustomView<YouBinding>(context, attrs, defStyleAttr),
    GenericAdapterView<Model> {
    override fun onBind(model: Model, position: Int, extraObject: Any?) {
    }
}

and finally, append an item to the adapter

private val adapter = AppGenericAdapter().apply {
    provider { context ->
        YourItem (context,)// if you want to pass extra data you can pass data as arg
    }
    provider { context ->
        YourItemButton(context,)// if you want to pass extra data you can pass data as arg
    }
}

binding.recycler.adapter = adapter
adapter.addSectionsAndNotify<YourItem , Model>(data)
// you can check with if the last item add this item
adapter.addSectionsAndNotify<YourItemButton , Model>(data)

如何在回收器视图(Kotlin)的末端添加按钮?

计㈡愣 2025-02-20 04:28:27
def NOTgate(a):
    return not a
print(NOTgate(1))

notgate truth table  
   input |  output
      1         0
      0         1

因此,返回未输入

def NOTgate(a):
    return not a
print(NOTgate(1))

notgate truth table  
   input |  output
      1         0
      0         1

so return the not input

如何以x(bar)输入x作为x返回

计㈡愣 2025-02-19 09:17:01

对UndoableJtextField类的更新,以避免一些编译器警告(JDK21)。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;

public class UndoableTextField extends JTextField {
    KeyStroke undoKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z,
                                                InputEvent.CTRL_DOWN_MASK);
    KeyStroke redoKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y,
                                                InputEvent.CTRL_DOWN_MASK);

    public UndoableTextField() {
        UndoManager undoManager = new UndoManager();
        getDocument().addUndoableEditListener(new UndoableEditListener() {
            @Override
            public void undoableEditHappened(UndoableEditEvent e) {
                undoManager.addEdit(e.getEdit());
            }
        });

        getInputMap().put(undoKeyStroke, "undoKeyStroke");
        getActionMap().put("undoKeyStroke", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    undoManager.undo();
                }
                catch (CannotUndoException cue) {
                }
            }
        });

        getInputMap().put(redoKeyStroke, "redoKeyStroke");
        getActionMap().put("redoKeyStroke", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    undoManager.redo();
                } 
                catch (CannotRedoException cre) {
                }
            }
        });
    }
}

An update to the UndoableJTextField class to avoid some compiler warnings (jdk21).

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.undo.*;

public class UndoableTextField extends JTextField {
    KeyStroke undoKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z,
                                                InputEvent.CTRL_DOWN_MASK);
    KeyStroke redoKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y,
                                                InputEvent.CTRL_DOWN_MASK);

    public UndoableTextField() {
        UndoManager undoManager = new UndoManager();
        getDocument().addUndoableEditListener(new UndoableEditListener() {
            @Override
            public void undoableEditHappened(UndoableEditEvent e) {
                undoManager.addEdit(e.getEdit());
            }
        });

        getInputMap().put(undoKeyStroke, "undoKeyStroke");
        getActionMap().put("undoKeyStroke", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    undoManager.undo();
                }
                catch (CannotUndoException cue) {
                }
            }
        });

        getInputMap().put(redoKeyStroke, "redoKeyStroke");
        getActionMap().put("redoKeyStroke", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    undoManager.redo();
                } 
                catch (CannotRedoException cre) {
                }
            }
        });
    }
}

创建一个不贵的jtextfield

计㈡愣 2025-02-19 06:15:35

这很简单。您没有任何jQuery文件,但是代码中想要使用jQuery对象。您要么必须删除包含jQuery的代码,要么必须使用jquery.min.js。

并要手动加入js文件,请关注此 https://developer.wordpress.org/themes/basics/including-css-javascript/

谢谢

This is pretty simple. You have no any jquery file but in code wanted to use the jQuery object. Either you have to remove the code where contain the jQuery or you have to use the jquery.min.js.

And to manually enqueue the js file please follow this https://developer.wordpress.org/themes/basics/including-css-javascript/

Thank you

我删除jquery.min.js wordpress时的问题

计㈡愣 2025-02-18 20:25:36

您需要在两个数据范围内将键标准化,才能合并它们。
一个想法是创建一个函数来处理 player_nationalities 中的全名,并在播放器名称的处理值上合并。例如:

def convert_player_name(name):
    try:
        first_name, last_name = name.split(' ', maxsplit=1)
        return f'{first_name[0]}. {last_name}'
    except ValueError:
        return name

    

player_nationalities['processed_name'] = [convert_player_name(name) for name in player_nationalities['Player']]
df_merged = player_nationalities.merge(player_ratings, left_on='processed_name', right_on='Player')

[out]

               Player_x Nationality processed_name       Player_y  Rating
0         Kylian Mbappé      France      K. Mbappé      K. Mbappé      93
1     Wissam Ben Yedder      France  W. Ben Yedder  W. Ben Yedder      89
2  Gianluigi Donnarumma       Italy  G. Donnarumma  G. Donnarumma      91

You would need to normalize the keys in both DataFrames in order to merge them.
One idea would be to create a function to process the full name in player_nationalities and merge on the processed value for player name. eg:

def convert_player_name(name):
    try:
        first_name, last_name = name.split(' ', maxsplit=1)
        return f'{first_name[0]}. {last_name}'
    except ValueError:
        return name

    

player_nationalities['processed_name'] = [convert_player_name(name) for name in player_nationalities['Player']]
df_merged = player_nationalities.merge(player_ratings, left_on='processed_name', right_on='Player')

[out]

               Player_x Nationality processed_name       Player_y  Rating
0         Kylian Mbappé      France      K. Mbappé      K. Mbappé      93
1     Wissam Ben Yedder      France  W. Ben Yedder  W. Ben Yedder      89
2  Gianluigi Donnarumma       Italy  G. Donnarumma  G. Donnarumma      91

在熊猫中合并人的名字

计㈡愣 2025-02-18 08:48:01
  1. 请参阅官方参考如何获得颜色
    标准颜色集的名称。您可以在一个中获得颜色名称
    列表。

  2. 关于控制重复的传奇,我个人没有
    我使用方法的问题,这是一种常见的方法,
    但是,如果我要编程处理,我会使用 set()
    通过添加重复的传奇名称来使其与众不同。我学到了这个
    提示来自 a>。


  3. 第三个是按类别订购,您可以指定上升或
    按类别下降订单。

这是没有得到预期答案的人的回应。我以前的答案不令人满意?我会尽可能回复。

import pandas as pd
import numpy as np
from plotly import graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px

# https://plotly.com/python/discrete-color/#color-sequences-in-plotly-express
plotly_default = px.colors.qualitative.Plotly
print(plotly_default)

fig = make_subplots(rows=2, cols=1, subplot_titles=["Value 1 dist", "Value 2 dist"])

fill_colors = {"a": plotly_default[0], "b": plotly_default[1]}

for i, val in enumerate(["val1", "val2"]):
    for c in df["cat"].unique():
        dff = df[df["cat"] == c]
        fig.add_trace(
            go.Box(
                y=dff[val],
                x=dff["cat"],
                boxmean="sd",
                name=c,
                showlegend=True, # if val=="val1" else False,
                fillcolor=fill_colors[c],
                line={"color": fill_colors[c]},
                opacity=0.5
            ),
            row=i + 1,
            col=1,
        )
names = set()
fig.for_each_trace(
    lambda trace:
        trace.update(showlegend=False)
        if (trace.name in names) else names.add(trace.name))

fig.update_xaxes(categoryorder='category ascending')
fig.update_layout(legend=dict(traceorder='reversed'))
fig.show()

  1. Please refer to the official reference for how to get the color
    names for a standard color set. You can get the color names in a
    list.

  2. As for controlling duplicate legends, I personally don't have a
    problem with your method as I use it and it is a common approach,
    but if I were to handle it programmatically, I would use set() to
    make it unique by adding the duplicate legend names. I learned this
    Tips from this answer.

  3. The third is to order by category, you can specify ascending or
    descending order by category.

This is a response from someone who did not get the expected answer. What was unsatisfactory about my previous answers? I will respond whenever possible.

import pandas as pd
import numpy as np
from plotly import graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px

# https://plotly.com/python/discrete-color/#color-sequences-in-plotly-express
plotly_default = px.colors.qualitative.Plotly
print(plotly_default)

fig = make_subplots(rows=2, cols=1, subplot_titles=["Value 1 dist", "Value 2 dist"])

fill_colors = {"a": plotly_default[0], "b": plotly_default[1]}

for i, val in enumerate(["val1", "val2"]):
    for c in df["cat"].unique():
        dff = df[df["cat"] == c]
        fig.add_trace(
            go.Box(
                y=dff[val],
                x=dff["cat"],
                boxmean="sd",
                name=c,
                showlegend=True, # if val=="val1" else False,
                fillcolor=fill_colors[c],
                line={"color": fill_colors[c]},
                opacity=0.5
            ),
            row=i + 1,
            col=1,
        )
names = set()
fig.for_each_trace(
    lambda trace:
        trace.update(showlegend=False)
        if (trace.name in names) else names.add(trace.name))

fig.update_xaxes(categoryorder='category ascending')
fig.update_layout(legend=dict(traceorder='reversed'))
fig.show()

enter image description here

与多个类别的块框图

计㈡愣 2025-02-18 04:14:00

功能已过时。

c.me.permissions.has("SEND_MESSAGES")

您的 haspermission -overwrites“ rel =” nofollow noreferrer“> https://discordjs.guide/popular-topics/permissions.html#channel-overwrites

Your hasPermission function is outdated with discord.js v13, you have now to use:

c.me.permissions.has("SEND_MESSAGES")

More informations here: https://discordjs.guide/popular-topics/permissions.html#channel-overwrites

是否可以找到机器人有权输入的频道?

计㈡愣 2025-02-17 22:18:11

您可以使用 方法

N = 10
psi = tensor(fock(N, 0), fock(N, 1), fock(N, 2))
goal_psi = tensor(fock(N, 0), fock(N, 2), fock(N, 1))
new_psi = psi.permute([0, 2, 1])
isequal(new_psi, goal_psi)

You can use the permute() method

N = 10
psi = tensor(fock(N, 0), fock(N, 1), fock(N, 2))
goal_psi = tensor(fock(N, 0), fock(N, 2), fock(N, 1))
new_psi = psi.permute([0, 2, 1])
isequal(new_psi, goal_psi)

在张量中移动状态(QUTIP)

计㈡愣 2025-02-17 20:53:47

是的,就像我想的那样明显和愚蠢。

我没有删除副本并添加剩余的对象作为关系,而只将其删除并将其添加到集合中。

这是一个巧合,只有第一作者留下来。

而不是

for case let author as Author in authors {
    if let authorsBooks = author.books as? NSMutableSet {
        if authorsBooks.contains(book) {
            authorsBooks.remove(book)
             authorsBooks.add(winner)
        }
    }

}

应该是

if let authors = book.authors as? Set<Author> {
    for author in authors {
        author.removeFromBooks(book)
        author.addToBooks(winner)
    }
}

Yep, it was as obvious and stupid as I thought.

Instead of removing the duplicate and adding the remaining object as a relationship, I only removed and added it to the set.

It was a coincidence that only the first author remained.

Instead of

for case let author as Author in authors {
    if let authorsBooks = author.books as? NSMutableSet {
        if authorsBooks.contains(book) {
            authorsBooks.remove(book)
             authorsBooks.add(winner)
        }
    }

}

It should have been

if let authors = book.authors as? Set<Author> {
    for author in authors {
        author.removeFromBooks(book)
        author.addToBooks(winner)
    }
}

核心数据,CloudKit-删除重复功能删除超出预期的

计㈡愣 2025-02-17 20:03:50

添加

#a_logout{
  width: 100%;
  position: absolute;
  bottom: 0;
}

Add

#a_logout{
  width: 100%;
  position: absolute;
  bottom: 0;
}

侧栏 - 菜单中的位置注销

计㈡愣 2025-02-17 07:29:46

这是一种方法。
iouc,结果将是DFS。如果您需要制作数组,则可以使用“ .values”或“ .to_numpy()”到过滤器的末尾,

for col in df.columns[1:]:
    vars()['df'+col] = df.filter(['c1',col])
    print(vars()['df'+col])

它会导致由名称创建为DFC1,DFC2,DFC2,DFC50的数据框。您可以访问

   c1  c2
0   1   2
1   5   8
2   6   9
3   7   2
   c1  c3
0   1  33
1   5  93
2   6  33
3   7  32
   c1  c50
0   1   46
1   5  456
2   6  456
3   7  434

here is one way to do it.
IIUC that the result will be DFs. if you need to make an array, you can use append either ".values" or ".to_numpy()" to the end of filter

for col in df.columns[1:]:
    vars()['df'+col] = df.filter(['c1',col])
    print(vars()['df'+col])

it results in dataframes created by names as dfc1, dfc2, dfc50. That you can access

   c1  c2
0   1   2
1   5   8
2   6   9
3   7   2
   c1  c3
0   1  33
1   5  93
2   6  33
3   7  32
   c1  c50
0   1   46
1   5  456
2   6  456
3   7  434

将矩阵分开并保存在Python中的单独列表或数组中?

计㈡愣 2025-02-16 16:14:25

确保您提交按钮是类型提交而不是类型按钮。

Make sure you submit button is of type submit rather than type button.

HTML表格未提交数据?

计㈡愣 2025-02-16 15:28:43

您只需通过使用 array.sort() 并通过使用 set> set() 方法,然后从 1st index访问亚军得分大批。

实时演示

// Input array
const scores = [5,2,3,6,6,5];

// Sort the array in descending order and remove the duplicates by using Set() method.
const sortedScores = [...new Set(scores.sort((a,b) => b-a))];

// Runner Up score by accesing the 1st index value.
console.log(sortedScores[1]);

You can simply achieve it by sort the array in descending order by using Array.sort() and filtered out the duplicates by using Set() method and then access the runner-up score from 1st index of the array.

Live Demo :

// Input array
const scores = [5,2,3,6,6,5];

// Sort the array in descending order and remove the duplicates by using Set() method.
const sortedScores = [...new Set(scores.sort((a,b) => b-a))];

// Runner Up score by accesing the 1st index value.
console.log(sortedScores[1]);

亚军上的得分 - JavaScript中的解决方案

计㈡愣 2025-02-16 05:03:41

已解决:

替换 - &gt;首先用 - &gt;值返回单个值,在那里您可以扣除替换

->first('leave_entitlement') 

->value('leave_entitlement')

Solved:

Replace ->first with ->value to return a single value and there you can do the deductions

->first('leave_entitlement') 

replace with

->value('leave_entitlement')

类STDClass的对象无法转换为INT表示什么

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

更多

友情链接

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文